Settings
Application settings and preferences view component
Settings
The Settings view provides a centralized interface for managing application configuration, user preferences, account settings, and integrations. It organizes settings into logical sections with sidebar navigation.
Type Signature
interface SettingsViewProps {
/** Page title */
title?: string
/** Page description */
description?: string
/** View layout mode */
layout?: 'single' | 'column' | 'canvas' | 'vibe'
/** Settings sections */
sections?: Array<{
id: string
label: string
icon?: string
content: React.ReactNode
}>
/** Active section */
activeSection?: string
/** Show navigation sidebar */
showSidebar?: boolean
/** Allow reset to defaults */
allowReset?: boolean
/** Page-level action buttons */
actions?: Array<{
id: string
label: string
icon?: string
onClick?: () => void
variant?: 'default' | 'primary' | 'destructive'
}>
/** Child content */
children?: React.ReactNode
}Usage
<App name="Acme Dashboard">
<Shell>
<SettingsView
title="Settings"
showSidebar={true}
allowReset={true}
sections={[
{
id: 'general',
label: 'General',
icon: 'Settings',
content: <GeneralSettings />
},
{
id: 'account',
label: 'Account',
icon: 'User',
content: <AccountSettings />
},
{
id: 'billing',
label: 'Billing',
icon: 'CreditCard',
content: <BillingSettings />
}
]}
/>
</Shell>
</App>Props
title
The page title displayed in the header. Defaults to "Settings".
<SettingsView title="Preferences">description
Optional page description.
<SettingsView
title="Settings"
description="Manage your account and application preferences"
>layout
Layout mode for the settings content. Defaults to 'single'.
// Single column layout with sidebar (default)
<SettingsView layout="single">
// Multi-column layout
<SettingsView layout="column">sections
Array of settings sections with their content.
<SettingsView
sections={[
{
id: 'profile',
label: 'Profile',
icon: 'User',
content: <ProfileSettings />
},
{
id: 'security',
label: 'Security',
icon: 'Lock',
content: <SecuritySettings />
},
{
id: 'notifications',
label: 'Notifications',
icon: 'Bell',
content: <NotificationSettings />
},
{
id: 'integrations',
label: 'Integrations',
icon: 'Puzzle',
content: <IntegrationSettings />
}
]}
/>activeSection
The currently selected section ID. Used for controlled navigation.
const [section, setSection] = useState('profile')
<SettingsView
activeSection={section}
onSectionChange={setSection}
sections={sections}
/>showSidebar
Controls whether the settings navigation sidebar is rendered. Defaults to true.
// Show sidebar (default)
<SettingsView showSidebar={true}>
// Hide sidebar (single section)
<SettingsView showSidebar={false}>
<GeneralSettings />
</SettingsView>allowReset
Enable "Reset to Defaults" functionality. Defaults to true.
<SettingsView allowReset={true}>
{/* Shows reset button in each section */}
</SettingsView>actions
Page-level action buttons displayed in the header.
<SettingsView
actions={[
{
id: 'save',
label: 'Save Changes',
variant: 'primary',
onClick: () => saveSettings()
},
{
id: 'cancel',
label: 'Cancel',
onClick: () => resetForm()
}
]}
>Layout Structure
The Settings view uses a sidebar navigation pattern:
┌─────────────────────────────────────┐
│ Settings │
├──────────┬──────────────────────────┤
│ General │ │
│ Account │ General Settings │
│ Security │ │
│ Billing │ [Form fields...] │
│ │ │
└──────────┴──────────────────────────┘Without Sidebar
For single-section settings:
┌─────────────────────────────────────┐
│ Settings │
├─────────────────────────────────────┤
│ │
│ General Settings │
│ │
│ [Form fields...] │
│ │
└─────────────────────────────────────┘Common Settings Sections
General Settings
Application-wide preferences:
<SettingsView
sections={[
{
id: 'general',
label: 'General',
icon: 'Settings',
content: (
<>
<FormField label="App Name" name="name" />
<FormField label="Language" name="language" type="select" />
<FormField label="Timezone" name="timezone" type="select" />
<FormField label="Date Format" name="dateFormat" type="select" />
</>
)
}
]}
/>Account Settings
User account management:
{
id: 'account',
label: 'Account',
icon: 'User',
content: (
<>
<FormField label="Email" name="email" type="email" />
<FormField label="Display Name" name="displayName" />
<FormField label="Avatar" name="avatar" type="file" />
<FormField label="Bio" name="bio" type="textarea" />
</>
)
}Security Settings
Password and authentication:
{
id: 'security',
label: 'Security',
icon: 'Lock',
content: (
<>
<FormField label="Current Password" name="currentPassword" type="password" />
<FormField label="New Password" name="newPassword" type="password" />
<FormField label="Confirm Password" name="confirmPassword" type="password" />
<Switch label="Two-Factor Authentication" name="twoFactor" />
<Button variant="destructive">Revoke All Sessions</Button>
</>
)
}Notification Settings
Email and push notification preferences:
{
id: 'notifications',
label: 'Notifications',
icon: 'Bell',
content: (
<>
<Switch label="Email Notifications" name="emailNotifications" />
<Switch label="Push Notifications" name="pushNotifications" />
<CheckboxGroup
label="Notification Types"
options={[
{ value: 'updates', label: 'Product Updates' },
{ value: 'marketing', label: 'Marketing Emails' },
{ value: 'security', label: 'Security Alerts' }
]}
/>
</>
)
}Billing Settings
Subscription and payment information:
{
id: 'billing',
label: 'Billing',
icon: 'CreditCard',
content: (
<>
<PlanCard current={currentPlan} />
<PaymentMethodCard card={paymentMethod} />
<InvoiceHistory invoices={invoices} />
<Button variant="destructive">Cancel Subscription</Button>
</>
)
}Integration Settings
Third-party service connections:
{
id: 'integrations',
label: 'Integrations',
icon: 'Puzzle',
content: (
<>
<IntegrationCard
name="Slack"
connected={true}
onDisconnect={() => {}}
/>
<IntegrationCard
name="GitHub"
connected={false}
onConnect={() => {}}
/>
<IntegrationCard
name="Google"
connected={true}
onDisconnect={() => {}}
/>
</>
)
}App Type Specializations
Different app types include different settings:
DeveloperApp Settings
<SettingsView
sections={[
{ id: 'general', label: 'General', content: <GeneralSettings /> },
{ id: 'api', label: 'API', content: <APISettings /> },
{ id: 'webhooks', label: 'Webhooks', content: <WebhookSettings /> },
{ id: 'security', label: 'Security', content: <SecuritySettings /> }
]}
/>AdminApp Settings
<SettingsView
sections={[
{ id: 'general', label: 'General', content: <GeneralSettings /> },
{ id: 'users', label: 'Users', content: <UserSettings /> },
{ id: 'roles', label: 'Roles', content: <RoleSettings /> },
{ id: 'system', label: 'System', content: <SystemSettings /> },
{ id: 'audit', label: 'Audit Logs', content: <AuditSettings /> }
]}
/>SaaSApp Settings
<SettingsView
sections={[
{ id: 'profile', label: 'Profile', content: <ProfileSettings /> },
{ id: 'team', label: 'Team', content: <TeamSettings /> },
{ id: 'billing', label: 'Billing', content: <BillingSettings /> },
{ id: 'integrations', label: 'Integrations', content: <IntegrationSettings /> },
{ id: 'notifications', label: 'Notifications', content: <NotificationSettings /> }
]}
/>Form Handling
Settings views typically contain forms:
const handleSave = async (values: SettingsFormValues) => {
await updateSettings(values)
toast.success('Settings saved')
}
<SettingsView
sections={[
{
id: 'general',
label: 'General',
content: (
<Form onSubmit={handleSave}>
<FormField label="App Name" name="name" />
<FormField label="Description" name="description" />
<FormActions>
<Button type="submit">Save Changes</Button>
<Button variant="ghost" onClick={resetForm}>Cancel</Button>
</FormActions>
</Form>
)
}
]}
/>Validation
Validate settings before saving:
const schema = z.object({
email: z.string().email(),
name: z.string().min(2),
timezone: z.string()
})
<SettingsView>
<Form schema={schema} onSubmit={handleSave}>
{/* Form fields */}
</Form>
</SettingsView>Responsive Behavior
Settings adapt to screen size:
Desktop (≥1024px)
┌────────────────────────────────────┐
│ Settings │
├──────────┬─────────────────────────┤
│ General │ │
│ Account │ Form Fields │
│ Security │ │
│ Billing │ [Settings content] │
└──────────┴─────────────────────────┘
Sidebar + contentMobile (under 1024px)
┌────────────────────────────────────┐
│ Settings │
├────────────────────────────────────┤
│ [Section Dropdown] │
├────────────────────────────────────┤
│ │
│ Form Fields │
│ │
│ [Settings content] │
└────────────────────────────────────┘
Dropdown navigation + contentAuto-Save
Implement auto-save for better UX:
const [settings, setSettings] = useState(initialSettings)
useEffect(() => {
const timer = setTimeout(() => {
saveSettings(settings)
}, 1000)
return () => clearTimeout(timer)
}, [settings])
<SettingsView>
<FormField
value={settings.name}
onChange={(value) => setSettings({ ...settings, name: value })}
/>
<SaveIndicator status="saved" />
</SettingsView>Reset to Defaults
Allow users to reset settings:
<SettingsView
allowReset={true}
sections={[
{
id: 'general',
label: 'General',
content: (
<>
<FormFields />
<Button
variant="destructive"
onClick={() => resetToDefaults('general')}
>
Reset to Defaults
</Button>
</>
)
}
]}
/>Integration with Payload CMS
Settings can auto-wire to Payload collections:
// Auto-fetches from Payload 'settings' collection
<SettingsView collection="settings">
<GeneralSettings />
</SettingsView>Best Practices
Group Related Settings
Organize settings into logical sections:
// Good - clear organization
<SettingsView
sections={[
{ id: 'profile', label: 'Profile', ... },
{ id: 'security', label: 'Security', ... },
{ id: 'notifications', label: 'Notifications', ... }
]}
/>
// Bad - flat list of unrelated settings
<SettingsView>
<FormField label="Name" />
<FormField label="Password" />
<FormField label="Email Notifications" />
{/* ... mixed settings */}
</SettingsView>Provide Clear Labels
Use descriptive labels and help text:
<FormField
label="API Rate Limit"
name="rateLimit"
description="Maximum requests per minute. Contact support to increase."
placeholder="100"
/>Show Unsaved Changes
Warn before leaving with unsaved changes:
const [hasChanges, setHasChanges] = useState(false)
useEffect(() => {
const handler = (e: BeforeUnloadEvent) => {
if (hasChanges) {
e.preventDefault()
e.returnValue = ''
}
}
window.addEventListener('beforeunload', handler)
return () => window.removeEventListener('beforeunload', handler)
}, [hasChanges])Handle Errors Gracefully
Show validation errors clearly:
<SettingsView>
<Form onSubmit={handleSave} onError={handleError}>
<FormField
label="Email"
name="email"
error={errors.email}
/>
</Form>
</SettingsView>Accessibility
Settings views implement accessibility features:
- Keyboard navigation - Tab through form fields
- Form labels - All inputs have associated labels
- Error announcements - Screen readers announce validation errors
- Focus management - Focus moves to first error on submit
<SettingsView aria-label="Application settings">
<section aria-labelledby="general-heading">
<h2 id="general-heading">General Settings</h2>
<Form>
<FormField
label="App Name"
name="name"
required
aria-describedby="name-description"
/>
<span id="name-description" className="sr-only">
The name displayed in the browser tab and app header
</span>
</Form>
</section>
</SettingsView>