Frontend Sidebar Feature Patterns
Read rules/frontend.md first for core architecture, routing, and project conventions.
The src/features/settings/ feature is the primary reference implementation for this pattern.
When to Use This Pattern
Use for any feature that has:
- Multiple sub-pages with sidebar navigation
- Complex forms requiring separate pages
- User preferences or settings
- Administrative panels with different categories
- Any feature where users navigate between related sub-sections
Folder Structure
src/features/[feature]/
├── index.tsx # Main layout component with sidebar + Outlet
├── components/
│ ├── sidebar-nav.tsx # Sidebar navigation component
│ └── content-section.tsx # Reusable content wrapper
└── [section]/ # Individual sections
├── index.tsx # Section wrapper using ContentSection
├── [section]-form.tsx # Main form component
├── data/
│ ├── schema.ts # Zod validation schemas
│ └── data.ts # GraphQL queries/mutations
├── hooks/
│ └── use-[feature]-[section].ts # Custom hooks
└── components/ # Form field components
└── [section]-form-fields.tsx
Navigation Structure
[Feature] Layout (src/features/[feature]/index.tsx)
├── Sidebar Navigation (SidebarNav component)
└── Content Area (Outlet for nested routes)
├── [Section1] (default route) → ContentSection → [Section1]Form
├── [Section2] → ContentSection → [Section2]Form
└── [SectionN] → ContentSection → [SectionN]Form
Routing Pattern
- Parent Route:
/_authenticated/[path]/[feature]— renders main[Feature]layout component - Default Child Route:
/_authenticated/[path]/[feature]/— renders default section - Other Child Routes:
/_authenticated/[path]/[feature]/[section2], etc.
Component Patterns
Main Layout Component (index.tsx)
- Renders
SidebarNav+<Outlet /> - Responsive layout: stacked on mobile, side-by-side on desktop
- Includes page title, description, and
<Separator /> - Template: Copy from
src/features/settings/index.tsx
ContentSection Wrapper
- Wraps each section with consistent title, description, separator, scrollable area
- Template: Copy from
src/features/settings/components/content-section.tsx - Use
lg:max-w-4xlfor optimal width
Section Form Components
- Data Fetching:
use[Feature][Section]()hook - Mutations:
useUpdate[Feature][Section]()hook - Validation: Zod schemas in
data/schema.ts - Error Handling:
useServerHandlersfor success/error notifications
Hook Implementation Pattern
// Data fetching hook
export const use[Feature][Section] = () => {
return useGraphQLQueryNew<[Feature][Section]Query, [Feature][Section]Query['data'], [Feature][Section]QueryVariables>(
['[feature]-[section]'],
[Feature][Section]Document,
(data) => data,
undefined
)
}
// Mutation hook
export function useUpdate[Feature][Section]() {
const { t } = useTranslation()
const { handleServerSuccess, handleServerError } = useServerHandlers()
const { mutateAsync, isPending, isError } = useGraphQLMutationNew<...>(
update[Feature][Section],
(data) => data.update[Feature],
{
onSuccess: (data, variables) => {
handleServerSuccess(variables.input, data, t('[feature].updated.success'), [['[feature]-[section]']])
},
onError: (error, variables) => handleServerError(error, variables.input, t('[feature].updated.error')),
}
)
return { mutateAsync, isPending, isError }
}
Sidebar Navigation Data
Add to src/components/layout/data/sidebar-data.tsx:
export function get[Feature]NavItems() {
return [
{
title: '[feature].sidebar.[section1]',
href: '/[path]/[feature]',
icon: <Icon1 size={18} />,
},
{
title: '[feature].sidebar.[section2]',
href: '/[path]/[feature]/[section2]',
icon: <Icon2 size={18} />,
},
]
}
Appearance Settings Best Practices
- Hover Effects: Add hover states to RadioGroupItem components for better UX feedback
- Grid Layout: Use
grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 - Icon Integration: Include preview icons with proper spacing
- Form Validation: Zod schemas for all form fields
Implementation Checklist
- Feature added to sidebar navigation data (
sidebar-data.tsx) - Parent route created at
src/routes/_authenticated/[path]/[feature]/ - Child routes created for each section
- Main layout component with
SidebarNav+Outlet -
ContentSectionwrapper component - Zod schemas defined in each section's
data/schema.ts - GraphQL queries/mutations in each section's
data/data.ts - Custom hooks in
hooks/use-[feature]-[section].ts - Form components with validation and submission
- Translation keys added to
en.ts,ja.ts,de.ts - Navigation items added to
sidebar-data.tsx - TypeScript compilation passes
- GraphQL codegen updated (if new queries added)
-
lg:max-w-4xlused for ContentSection width
Reference Implementation
src/features/settings/— full example with 5 sections (Profile, Account, Appearance, Notifications, Display)src/routes/_authenticated/p/$userSlug/settings/— route structuresrc/components/layout/data/sidebar-data.tsx— navigation data pattern