Skip to main content

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

[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-4xl for 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: useServerHandlers for 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 }
}

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
  • ContentSection wrapper 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-4xl used 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 structure
  • src/components/layout/data/sidebar-data.tsx — navigation data pattern