Sofondo Framework Configuration Guide
The Sofondo Framework provides a comprehensive configuration system that allows you to customize behavior, appearance, and features without modifying component code.
Table of Contents
- Quick Start
- Configuration File
- Configuration Options
- Using Configuration
- TypeScript Support
- Examples
Quick Start
- Create a configuration file:
// sofondo.config.ts
import { defineConfig } from '@sofondo/core';
export default defineConfig({
theme: {
defaultMode: 'dark',
},
sidebar: {
defaultCollapsed: true,
},
});
- Use ConfigProvider in your app:
// app/layout.tsx
import { ConfigProvider } from '@sofondo/react';
import config from '../sofondo.config';
export default function RootLayout({ children }) {
return (
<html>
<body>
<ConfigProvider config={config}>
{children}
</ConfigProvider>
</body>
</html>
);
}
- Access configuration in components:
import { useConfig, useConfigSection } from '@sofondo/react';
function MyComponent() {
// Get entire config
const config = useConfig();
// Or get specific section
const sidebarConfig = useConfigSection('sidebar');
return <div>{/* your component */}</div>;
}
Configuration File
The configuration file should export a configuration object using the defineConfig helper:
// sofondo.config.ts
import { defineConfig } from '@sofondo/core';
export default defineConfig({
// Your configuration here
});
Why use defineConfig?
- Provides TypeScript autocomplete
- Validates configuration at design time
- Documents available options
- No runtime overhead (it just returns the object)
Configuration Options
Theme
Control the appearance and theme behavior of your application.
theme: {
// Default theme mode
defaultMode: 'system', // 'light' | 'dark' | 'system'
// Enable theme switcher UI component
enableSwitcher: true,
// Custom CSS variable overrides
colors: {
light: {
'--primary': '#0066cc',
'--background': '#ffffff',
// ... more CSS variables
},
dark: {
'--primary': '#3399ff',
'--background': '#0a0a0a',
// ... more CSS variables
},
},
}
Options:
defaultMode: Initial theme (‘light’, ‘dark’, or ‘system’ to follow OS preference)enableSwitcher: Show/hide theme toggle buttoncolors: Override CSS custom properties for each theme
Sidebar
Configure sidebar behavior and appearance.
sidebar: {
// Start collapsed or expanded
defaultCollapsed: false,
// Sidebar width when expanded (pixels)
width: 240,
// Sidebar width when collapsed (pixels)
collapsedWidth: 60,
// Where to store sidebar state
storageStrategy: 'auto', // 'cookies' | 'localStorage' | 'sessionStorage' | 'memory' | 'auto'
// Show tooltips in collapsed mode
enableTooltips: true,
// Tooltip position offsets
tooltipOffset: {
x: 10,
y: 0,
},
}
Storage Strategies:
cookies: Persists across browser sessions, SSR-friendlylocalStorage: Persists across sessions, client-side onlysessionStorage: Cleared when tab closesmemory: Not persisted (resets on page reload)auto: Prefers cookies, falls back to localStorage
Animations
Control animations throughout the framework.
animations: {
// Enable/disable all animations
enabled: true,
// Animation speed multiplier
durationMultiplier: 1, // 0.5 = faster, 2 = slower
// Respect user's motion preferences
respectReducedMotion: true,
// Stagger delay for container animations (ms)
staggerDelay: 100,
}
Duration Multiplier Examples:
0.5: Animations run twice as fast1.0: Normal speed (default)2.0: Animations run twice as slow0: Instant (effectively disables animations)
Components
Set defaults for individual components.
Custom Scrollbar
components: {
scrollbar: {
enabled: true,
width: 6, // pixels
},
}
Skeleton Loaders
components: {
skeleton: {
enabled: true,
animation: 'pulse', // 'pulse' | 'wave' | 'none'
},
}
Toast Notifications
components: {
toast: {
position: 'top-right', // 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'
duration: 5000, // milliseconds
maxToasts: 3, // maximum simultaneous toasts
},
}
Data Grid
components: {
dataGrid: {
defaultPageSize: 10,
enablePagination: true,
enableSorting: true,
},
}
Accessibility
Configure accessibility features.
accessibility: {
// Enhanced keyboard navigation
keyboardNavigation: true,
// Show focus indicators
focusVisible: true,
// Announce page changes to screen readers
announceRouteChanges: true,
}
Development
Tools for development and debugging.
dev: {
// Show component boundaries
showComponentBoundaries: false,
// Performance monitoring
enablePerformanceMonitoring: false,
// Log config changes to console
logConfigChanges: false,
}
Using Configuration
In React Components
Get Entire Configuration
import { useConfig } from '@sofondo/react';
function MyComponent() {
const config = useConfig();
if (config.animations.enabled) {
// Use animations
}
return <div>...</div>;
}
Get Specific Section
import { useConfigSection } from '@sofondo/react';
function Sidebar() {
const sidebarConfig = useConfigSection('sidebar');
return (
<aside style={{ width: sidebarConfig.width }}>
{/* sidebar content */}
</aside>
);
}
Direct Props vs Configuration
Many components accept configuration via props OR read from ConfigProvider:
// Option 1: Via props (takes precedence)
<ToastProvider position="top-left" duration={3000} maxToasts={5}>
{children}
</ToastProvider>
// Option 2: Via ConfigProvider (set once, applies everywhere)
<ConfigProvider config={{ components: { toast: { position: 'top-left' } } }}>
<ToastProvider>
{children}
</ToastProvider>
</ConfigProvider>
Order of precedence:
- Component props (highest priority)
- ConfigProvider configuration
- Default values (lowest priority)
Without ConfigProvider
Components work without ConfigProvider using sensible defaults:
// This works fine - uses built-in defaults
function App() {
return (
<ThemeProvider>
<ToastProvider>
{/* your app */}
</ToastProvider>
</ThemeProvider>
);
}
TypeScript Support
The configuration system is fully typed:
import type { UserConfig, SofondoConfig } from '@sofondo/core';
// Full autocomplete and type checking
const config: UserConfig = {
theme: {
defaultMode: 'dark', // ✓ Autocompleted
// defaultMode: 'blue', // ✗ Type error
},
};
Available Types:
UserConfig: Partial configuration (all fields optional)SofondoConfig: Alias for UserConfigResolvedConfig: Complete configuration with all defaultsThemeConfig,SidebarConfig, etc.: Individual sections
Examples
Dark Mode by Default
export default defineConfig({
theme: {
defaultMode: 'dark',
},
});
Minimalist UI
export default defineConfig({
animations: {
enabled: false, // No animations
},
components: {
skeleton: {
enabled: false, // No skeleton loaders
},
scrollbar: {
enabled: false, // Use browser scrollbar
},
},
});
Accessibility First
export default defineConfig({
animations: {
respectReducedMotion: true,
durationMultiplier: 0.5, // Faster animations
},
accessibility: {
keyboardNavigation: true,
focusVisible: true,
announceRouteChanges: true,
},
});
Development Mode
export default defineConfig({
dev: {
showComponentBoundaries: true,
enablePerformanceMonitoring: true,
logConfigChanges: true,
},
});
Compact Sidebar
export default defineConfig({
sidebar: {
defaultCollapsed: true,
width: 200, // Narrower when expanded
collapsedWidth: 50, // Narrower when collapsed
},
});
Custom Toast Position
export default defineConfig({
components: {
toast: {
position: 'bottom-center',
duration: 3000,
maxToasts: 1, // Only show one toast at a time
},
},
});
Configuration Validation
The framework validates configuration and provides helpful error messages:
// Invalid configuration
defineConfig({
theme: {
defaultMode: 'blue', // ✗ Invalid value
},
});
// Error: Invalid theme.defaultMode: "blue". Must be one of: light, dark, system
Validation is performed:
- At build time (TypeScript)
- At runtime (when ConfigProvider mounts)
- In development mode (warnings in console)
Best Practices
- Use
defineConfigfor autocomplete and type safety - Keep configuration files small - only override what you need
- Use ConfigProvider once at the app root
- Validate configuration in development
- Document custom overrides for your team
- Test with different configurations to ensure flexibility
Troubleshooting
Configuration Not Applied
Problem: Changes to config file don’t take effect
Solutions:
- Restart dev server after config changes
- Check that ConfigProvider wraps your app
- Verify config import path is correct
- Check browser console for validation errors
TypeScript Errors
Problem: Type errors in configuration file
Solutions:
- Use
defineConfighelper - Check spelling of configuration keys
- Ensure values match allowed types
- Update
@sofondo/corepackage
Runtime Errors
Problem: “useConfig must be used within ConfigProvider”
Solution: Wrap your app with ConfigProvider:
<ConfigProvider config={config}>
<YourApp />
</ConfigProvider>
Migration from Hard-Coded Values
If you have hard-coded configuration values, migrate them to the config file:
Before:
<ToastProvider position="top-right" duration={5000}>
<ThemeProvider>
{children}
</ThemeProvider>
</ToastProvider>
After:
// sofondo.config.ts
export default defineConfig({
components: {
toast: {
position: 'top-right',
duration: 5000,
},
},
});
// app/layout.tsx
<ConfigProvider config={config}>
<ToastProvider>
<ThemeProvider>
{children}
</ThemeProvider>
</ToastProvider>
</ConfigProvider>