React Components
Customize published React components
React Components
OI Laravel Documentation publishes fully customizable React components to your project. After installation, all components are yours to modify completely.
Published Components Location
Components are published to:
resources/js/components/documentation/
All published components are standard React files using TypeScript, fully typed and ready to customize.
Component Structure
Layout Components
DocumentationLayout.tsx
The main wrapper component:
// resources/js/components/documentation/DocumentationLayout.tsx
export interface DocumentationLayoutProps {
children: React.ReactNode;
navigation: NavigationStructure;
currentPath: string;
}
export function DocumentationLayout({
children,
navigation,
currentPath,
}: DocumentationLayoutProps) {
return (
<div className="flex min-h-screen bg-white dark:bg-slate-950">
<DocumentationNavigation
navigation={navigation}
currentPath={currentPath}
/>
<main className="flex-1">
{children}
</main>
</div>
);
}Customization points:
- Sidebar width and styling
- Main content area styling
- Dark mode theme
- Responsive breakpoints
Navigation Components
DocumentationNavigation.tsx
The sidebar navigation component:
interface DocumentationNavigationProps {
navigation: NavigationStructure;
currentPath: string;
}
export function DocumentationNavigation({
navigation,
currentPath,
}: DocumentationNavigationProps) {
return (
<nav className="w-64 border-r border-slate-200 dark:border-slate-800">
{/* Sidebar content */}
</nav>
);
}Customizable aspects:
- Navigation styling
- Active link highlighting
- Nested section expansion
- Mobile/tablet behavior
DocumentationSearch.tsx
The search interface component:
interface DocumentationSearchProps {
onSearch: (query: string) => void;
isLoading?: boolean;
}
export function DocumentationSearch({
onSearch,
isLoading,
}: DocumentationSearchProps) {
return (
<div className="search-container">
{/* Search UI */}
</div>
);
}Customizable aspects:
- Search input styling
- Search result display
- Result relevance highlighting
- No results messaging
Content Components
DocumentationMarkdownContent.tsx
Renders markdown to React components:
interface DocumentationMarkdownContentProps {
content: string;
headings: string[];
}
export function DocumentationMarkdownContent({
content,
headings,
}: DocumentationMarkdownContentProps) {
return (
<div className="prose dark:prose-invert">
{/* Markdown rendered here */}
</div>
);
}Customizable aspects:
- Typography and spacing
- Code block styling
- Link formatting
- Image rendering
DocumentationTableOfContents.tsx
Displays page headings:
interface DocumentationTableOfContentsProps {
headings: HeadingItem[];
}
export function DocumentationTableOfContents({
headings,
}: DocumentationTableOfContentsProps) {
return (
<aside className="w-48">
{/* Table of contents */}
</aside>
);
}Customizable aspects:
- TOC positioning
- Heading hierarchy display
- Active heading highlighting
- Scroll synchronization
Navigation Flow Components
DocumentationPreviousNext.tsx
Shows previous and next page links:
interface DocumentationPreviousNextProps {
previous?: PageLink;
next?: PageLink;
}
export function DocumentationPreviousNext({
previous,
next,
}: DocumentationPreviousNextProps) {
return (
<div className="flex justify-between mt-8">
{/* Previous/Next buttons */}
</div>
);
}Component Customization Guide
Modifying Styling
Update Tailwind classes directly:
// Before
<nav className="w-64 border-r border-slate-200">
// After - Make it wider and change color
<nav className="w-80 border-r border-blue-200">Changing Layout Structure
Rearrange components:
export function DocumentationLayout() {
return (
<div className="flex flex-col">
<Header />
<div className="flex">
<Navigation />
<div className="flex-1">
<TOC />
<Content />
</div>
</div>
</div>
);
}Adding Custom Hooks
Use React hooks in components:
export function DocumentationNavigation() {
const [isExpanded, setIsExpanded] = useState(false);
const theme = useTheme();
const { pathname } = useLocation();
return (
<nav className={theme === 'dark' ? 'bg-slate-950' : 'bg-white'}>
{/* Updated navigation */}
</nav>
);
}Integrating UI Libraries
Add additional UI libraries:
import { Button } from '@/components/ui/button';
import { Sheet, SheetContent } from '@/components/ui/sheet';
export function DocumentationNavigation() {
return (
<Sheet>
<SheetContent>
{/* Mobile navigation */}
</SheetContent>
</Sheet>
);
}Publishing System Hooks
The components receive data through Inertia.js props:
// pages/Documentation.tsx
import { DocumentationLayout } from '@/components/documentation/DocumentationLayout';
export default function Documentation({
page,
navigation,
searchResults
}: Props) {
return (
<DocumentationLayout navigation={navigation}>
<DocumentationMarkdownContent content={page.content} />
</DocumentationLayout>
);
}Styling with Tailwind
All components use Tailwind CSS. Customize global styles:
/* resources/css/documentation.css */
@layer components {
.doc-heading {
@apply text-2xl font-bold text-slate-900 dark:text-white;
}
.doc-code {
@apply font-mono text-sm;
}
}Then use in components:
<h2 className="doc-heading">Title</h2>
<code className="doc-code">const x = 1;</code>Dark Mode Support
Components use Tailwind's dark mode:
<div className="bg-white dark:bg-slate-950">
<p className="text-slate-900 dark:text-white">
Content
</p>
</div>Customize dark mode in tailwind.config.js:
module.exports = {
darkMode: 'class',
theme: {
extend: {
colors: {
// Custom dark colors
}
}
}
}Component Props
All components accept standard React props:
interface ComponentProps extends React.HTMLAttributes<HTMLDivElement> {
// Custom props
data?: any;
onEvent?: () => void;
}You can pass additional props:
<DocumentationLayout
className="custom-layout"
id="my-docs"
data-test="documentation"
>
{/* Children */}
</DocumentationLayout>Common Customizations
Change Navigation Width
// DocumentationLayout.tsx
<aside className="w-80"> {/* Changed from w-64 */}Modify Code Block Styling
// DocumentationMarkdownContent.tsx
const codeBlockClasses = "bg-slate-900 text-white p-4 rounded-lg";Add Analytics Events
// DocumentationNavigation.tsx
const handleLinkClick = (path: string) => {
// Send to analytics
gtag('event', 'documentation_click', { path });
};Customize Search Results Display
// DocumentationSearch.tsx
const renderResult = (result: SearchResult) => (
<div className="custom-result-styling">
<h4>{result.title}</h4>
<p>{result.description}</p>
<span className="badge">{result.section}</span>
</div>
);Add Breadcrumbs
// DocumentationLayout.tsx
<Breadcrumbs path={currentPath} />
<DocumentationContent />TypeScript Support
All components are fully typed:
import type {
DocumentationPage,
NavigationStructure,
SearchResult
} from '@/types/documentation';
interface CustomComponentProps {
page: DocumentationPage;
navigation: NavigationStructure;
}Add your own types:
// types/documentation.ts
export interface CustomTheme {
primaryColor: string;
accentColor: string;
}Testing Components
Test custom components:
// __tests__/DocumentationLayout.test.tsx
import { render, screen } from '@testing-library/react';
import { DocumentationLayout } from '@/components/documentation/DocumentationLayout';
it('renders layout with navigation', () => {
render(<DocumentationLayout navigation={mockNav} />);
expect(screen.getByRole('navigation')).toBeInTheDocument();
});Performance Optimization
Memoize components to prevent unnecessary re-renders:
import { memo } from 'react';
export const DocumentationNavigation = memo(function DocumentationNavigation({
navigation,
}: DocumentationNavigationProps) {
return <nav>{/* Content */}</nav>;
});Use lazy loading for heavy components:
import { lazy, Suspense } from 'react';
const DocumentationSearch = lazy(() => import('./DocumentationSearch'));
export function DocumentationLayout() {
return (
<Suspense fallback={<div>Loading...</div>}>
<DocumentationSearch />
</Suspense>
);
}Accessibility (a11y)
Ensure components are accessible:
<button
aria-label="Toggle navigation"
aria-expanded={isOpen}
onClick={toggleNav}
>
{/* Content */}
</button>
<nav aria-label="Documentation navigation">
{/* Navigation */}
</nav>Best Practices
- Keep components focused - One responsibility per component
- Use TypeScript - Full type safety
- Document props - Use JSDoc comments
- Test changes - Especially after styling modifications
- Version components - Track breaking changes
- Maintain dark mode - Keep
dark:classes - Use semantic HTML - Proper accessibility
Component Map
Quick reference of all publishable components:
| Component | Purpose | File |
|---|---|---|
| DocumentationLayout | Main wrapper | DocumentationLayout.tsx |
| DocumentationNavigation | Sidebar menu | DocumentationNavigation.tsx |
| DocumentationSearch | Search interface | DocumentationSearch.tsx |
| DocumentationMarkdownContent | Markdown rendering | DocumentationMarkdownContent.tsx |
| DocumentationTableOfContents | Page headings | DocumentationTableOfContents.tsx |
| DocumentationPreviousNext | Navigation links | DocumentationPreviousNext.tsx |
| DocumentationHeader | Page header | DocumentationHeader.tsx |
| DocumentationFooter | Page footer | DocumentationFooter.tsx |
Next Steps
- Customize Search - Configure search behavior
- View Getting Started - Installation guide
- Write Content - Create documentation pages