Logitech Software Design System
npm install @ybaillet/elysiumA production-ready React + TypeScript component library with a Figma tokens-based design system, built for Electron desktop applications.
- Dual-theme support: G-Hub theme (Cyan primary #00B6FA) and Options+ theme (Teal primary #00FDCF)
- Light/Dark mode: Automatic mode switching with localStorage persistence
- Figma tokens: Single source of truth from Figma design tokens
- Accessible: Built with Radix UI primitives for full accessibility
- TypeScript: Full type safety with exported types
- Custom Font: BrownLogitechPan font family included (12 weights)
- 330+ Icons: Custom SVG icon library
``bash`
npm install @ybaillet/elysium
> Note: Peer dependencies (React, Radix UI primitives, etc.) are automatically installed with npm 7+. If you're using an older npm version, you may need to install them manually.
All 4 steps below are required for the components to display correctly.
Import the component styles in your main entry file. This includes the compiled Tailwind CSS classes used by all components:
`tsx`
// In your main.tsx or index.tsx (your app's entry point)
import '@ybaillet/elysium/styles';
Import the BrownLogitechPan font family for the authentic Logitech look:
`tsx`
import '@ybaillet/elysium/fonts';
The ThemeProvider is essential - it generates all CSS variables that components depend on. Without it, colors will not display correctly.
`tsx
// App.tsx
import { ThemeProvider } from '@ybaillet/elysium';
function App() {
return (
{/ Your entire app goes here /}
);
}
export default App;
`
Important: The ThemeProvider must wrap your entire application. It dynamically injects CSS variables (like --color-surface-primary-default, --color-text-neutral-default, etc.) that all components use for theming.
If your project uses Tailwind CSS, you must add the Elysium dist folder to your content paths. This ensures Tailwind doesn't purge the CSS classes used by Elysium components:
`js`
// tailwind.config.js
module.exports = {
content: [
'./src/*/.{js,ts,jsx,tsx}',
// Add this line - required for Elysium components to work
'./node_modules/@ybaillet/elysium/dist/*/.{js,cjs}',
],
// ... rest of your config
};
Here's a complete example of a properly configured app:
`tsx
// main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
// Step 1: Import Elysium styles
import '@ybaillet/elysium/styles';
// Step 2: Import fonts (optional)
import '@ybaillet/elysium/fonts';
// Your own styles (if any) should come after
import './index.css';
ReactDOM.createRoot(document.getElementById('root')!).render(
);
`
`tsx
// App.tsx
import { ThemeProvider, Button, Card, Switch } from '@ybaillet/elysium';
function App() {
return (
// Step 3: Wrap with ThemeProvider
);
}
export default App;
`
Colors not displaying correctly?
- Ensure ThemeProvider wraps your entire app (not just individual components)@ybaillet/elysium/styles
- Verify is imported in your entry filetailwind.config.js
- If using Tailwind, check that the Elysium content path is in your
Components look unstyled?
- Make sure styles are imported before your own CSS files
- Check browser console for any import errors
Elysium supports two branded themes, each with light and dark modes:
| Theme ID | Brand Name | Primary Color | Use Case |
|----------|------------|---------------|----------|
| ghub | G-Hub | Cyan (#00B6FA) | Gaming peripherals, high-energy interfaces |options+
| | Options+ | Teal (#00FDCF) | Professional peripherals, productivity tools |
> Note: The theme IDs match the brand names for clarity. The theme definition files are themeGHub.ts and themeOptionsPlus.ts.
Each theme automatically adjusts all component colors, including surfaces, text, icons, and interactive states.
Wrap your app with ThemeProvider and specify your theme:
`tsx
import { ThemeProvider, Button, Switch, Slider } from '@ybaillet/elysium';
// G-Hub theme (Cyan) - Dark mode
function GHubApp() {
return (
);
}
// Options+ theme (Teal) - Light mode
function OptionsPlusApp() {
return (
);
}
`
Use the useTheme hook to change themes or modes at runtime:
`tsx
import { useTheme, Button } from '@ybaillet/elysium';
function ThemeSwitcher() {
const { theme, mode, themeBrand, setTheme, setMode, toggleMode } = useTheme();
return (
Current: {themeBrand} ({mode})
$3
All components automatically adapt to the current theme. The primary color changes based on the active theme:
`tsx
import { ThemeProvider, Button, ProgressIndicator, Checkbox } from '@ybaillet/elysium';function MyApp() {
return (
{/ All these components use Cyan (G-Hub) accents /}
{/ Switching to options+ would make them all Teal instead /}
);
}
`Components
$3
| Component | Description |
|-----------|-------------|
| Accordion | Expandable content sections |
| Button | Primary interactive element with multiple variants |
| Card | Container with header, content, and footer |
| Checkbox | Toggle selection control |
| Dialog | Modal overlay for focused interactions |
| DropdownMenu | Context menu with nested options |
| IconButton | Icon-only button with aria-label |
| Input | Text input with validation states |
| ListItem | Interactive list row with various controls |
| Pagination | Page navigation control |
| ProgressIndicator | Visual progress display |
| RadioGroup | Single-select option group |
| Search | Search input with clear functionality |
| Select | Dropdown selection control |
| Slider | Range value selector |
| Snackbar | Toast notifications |
| Switch | Toggle control |
| Tabs | Horizontal tab navigation |
| TabsVertical | Vertical tab navigation |
| TabViewer | Tab content manager |
| Textarea | Multi-line text input |
| Tooltip | Contextual information popup |
$3
| Component | Description |
|-----------|-------------|
| ActuationPoint | Vertical slider for actuation settings |
| AssignmentLabel | Key assignment display |
| Connectivity | Device connection status indicator |
| RapidTrigger | Horizontal slider for rapid trigger settings |
Component Usage Examples
Many components require state management. Here are complete examples showing how to properly use them:
$3
`tsx
import { useState } from 'react';
import {
ActuationPoint,
RapidTrigger,
Slider,
Switch,
Checkbox,
Input,
Select,
SelectTrigger,
SelectValue,
SelectContent,
SelectItem
} from '@ybaillet/elysium';function ControlledComponentsExample() {
// Slider-based components
const [actuationValue, setActuationValue] = useState(1);
const [rapidTriggerValue, setRapidTriggerValue] = useState(0.5);
const [sliderValue, setSliderValue] = useState([50]);
// Toggle components
const [switchOn, setSwitchOn] = useState(false);
const [checked, setChecked] = useState(false);
// Text input
const [text, setText] = useState('');
// Select
const [selected, setSelected] = useState('option1');
return (
{/ ActuationPoint - vertical slider /}
value={actuationValue}
onChange={setActuationValue}
/>
{/ RapidTrigger - horizontal slider /}
value={rapidTriggerValue}
onChange={setRapidTriggerValue}
/>
{/ Standard Slider /}
value={sliderValue}
onValueChange={setSliderValue}
min={0}
max={100}
/>
{/ Switch toggle /}
checked={switchOn}
onCheckedChange={setSwitchOn}
/>
{/ Checkbox /}
checked={checked}
onCheckedChange={setChecked}
/>
{/ Text Input /}
value={text}
onChange={(e) => setText(e.target.value)}
placeholder="Type here..."
/>
{/ Select dropdown /}
);
}
`$3
Some components work without explicit state management:
`tsx
import { Button, Checkbox, Switch } from '@ybaillet/elysium';function UncontrolledExample() {
return (
{/ Button with click handler /}
{/ Checkbox with default value /}
{/ Switch with default value /}
);
}
`$3
| Component | Description |
|-----------|-------------|
| Navbar | Application header with navigation |
| DeviceNav | Device sidebar navigation |
| Sensitivity | DPI/Sensitivity control panel |
Icons
Access 330+ custom icons:
`tsx
import { Icons } from '@ybaillet/elysium';// Use any icon
`Tokens
The design system uses a 2-layer token architecture:
$3
Base color palette with literal hex values stored in
src/tokens/colors/raw.ts. These are the foundational colors that semantic tokens reference.`tsx
import { colorRaw } from '@ybaillet/elysium';// Examples of raw colors
colorRaw['Cyan-500'] // '#00B6FA' - G-Hub primary
colorRaw['Teal-500'] // '#00FDCF' - Options+ primary
colorRaw['Neutral-900'] // '#1A1A1A' - Dark background
colorRaw['Neutral-100'] // '#F5F5F5' - Light background
colorRaw['Red-500'] // '#FF4D4D' - Error state
colorRaw['Green-500'] // '#00C853' - Success state
`$3
Each brand has its own theme file for easy management and scalability:
`
src/tokens/colors/
├── raw.ts # Raw color palette (shared by all themes)
├── types.ts # Shared TypeScript types and utilities
├── themeGHub.ts # G-Hub theme (Cyan primary)
├── themeOptionsPlus.ts # Options+ theme (Teal primary)
└── themes.ts # Aggregator that merges all themes
`To add a new theme (e.g., themeC):
1. Copy
themeGHub.ts to themeNewBrand.ts
2. Update the BRAND_ID constant
3. Modify color references to use your brand's colors
4. Register in themes.ts:`tsx
// themes.ts
import { themeNewBrand, BRAND_ID as NEW_BRAND_ID } from './themeNewBrand';const THEMES = [
{ brandId: GHUB_ID, definition: themeGHub },
{ brandId: OPTIONS_PLUS_ID, definition: themeOptionsPlus },
{ brandId: NEW_BRAND_ID, definition: themeNewBrand }, // Add here
];
`5. Add brand config to
types.ts:`tsx
// types.ts
export const BRAND_REGISTRY: BrandConfig[] = [
{ id: 'G-Hub', name: 'G-Hub', lightKey: 'G-Hub-Light', darkKey: 'G-Hub-Dark' },
{ id: 'Options+', name: 'Options+', lightKey: 'Options+-Light', darkKey: 'Options+-Dark' },
{ id: 'NewBrand', name: 'NewBrand', lightKey: 'NewBrand-Light', darkKey: 'NewBrand-Dark' }, // Add here
];
`$3
Each theme file exports a
ThemeDefinition with light/dark color references:`tsx
// Example from themeGHub.ts
import { ThemeDefinition, ref } from './types';export const BRAND_ID = 'G-Hub';
export const themeGHub: ThemeDefinition = {
"surface-primary-default": {
light: ref("colors-cyan-500"), // References colorRaw['colors-cyan-500']
dark: ref("colors-cyan-500"),
},
"surface-background": {
light: ref("colors-gray-50"), // Light mode background
dark: ref("colors-gray-1000"), // Dark mode background
},
// ... more tokens
};
`$3
Theme-aware tokens that reference raw colors. Each semantic token has values for all 4 theme/mode combinations: G-Hub-Light, G-Hub-Dark, Options+-Light, Options+-Dark.
`tsx
import { colorsThemes, getSemanticColor } from '@ybaillet/elysium';// Semantic token categories:
// - surface-* : Background colors (surface-primary-default, surface-secondary, surface-dialog)
// - text-* : Text colors (text-primary, text-secondary, text-neutral-muted)
// - stroke-* : Border colors (stroke-primary-default, stroke-neutral-muted)
// - icon-* : Icon colors (icon-primary, icon-secondary)
// - interactive-*: Interactive element colors
// - background-* : Page background aliases (background-1000, background-975, background-950)
// Get resolved color value for a specific theme/mode
const bgColor = getSemanticColor('surface-primary-default', 'dark', 'G-Hub');
const textColor = getSemanticColor('text-neutral-default', 'light', 'Options+');
`$3
`tsx
import { dimensions, typography, getSpacing, getRadius } from '@ybaillet/elysium';// Spacing tokens
getSpacing('04') // '4px'
getSpacing('08') // '8px'
getSpacing('16') // '16px'
getSpacing('24') // '24px'
// Border radius tokens
getRadius('04') // '4px'
getRadius('08') // '8px'
getRadius('16') // '16px'
getRadius('full') // '9999px'
// Typography tokens include font sizes, weights, and line heights
`CSS Variables
The ThemeProvider injects CSS variables for all design tokens. You can use them directly:
`css
.my-component {
background: var(--color-surface-primary-default);
border-radius: var(--radius-08);
padding: var(--spacing-16);
}
`TypeScript Support
All components export their prop types:
`tsx
import type {
ButtonProps,
CardProps,
ThemeContextType,
ThemeName,
ThemeMode
} from '@ybaillet/elysium';
`Font Files
The BrownLogitechPan font is included with 12 weights:
- Thin (100) + Italic
- Light (300) + Italic
- Regular (400) + Italic
- Medium (500) + Italic
- Bold (700) + Italic
- Black (900) + Italic
Font files are located at
@ybaillet/elysium/fonts/*` if you need to reference them directly.- Chrome (latest)
- Firefox (latest)
- Safari (latest)
- Edge (latest)
- Electron (latest)
MIT