@ttoss/ui
React component library built on Theme UI for building consistent, accessible user interfaces with design token integration.
Installation
pnpm add @ttoss/ui @ttoss/react-icons @emotion/react @chakra-ui/react
ESM Only: This package requires ES modules support.
Quick Start
1. Setup Theme Provider
import { ThemeProvider } from '@ttoss/ui';
import { BruttalTheme } from '@ttoss/theme/Bruttal';
export const App = () => (
<ThemeProvider theme={BruttalTheme}>
<YourAppContent />
</ThemeProvider>
);
2. Use Components
import { Flex, Text, Button, Box } from '@ttoss/ui';
export const Example = () => (
<Box sx={{ padding: 'lg' }}>
<Text variant="heading">Welcome</Text>
<Flex sx={{ gap: 'md', flexDirection: 'column' }}>
<Button variant="primary">Get Started</Button>
<Text>
Access [design
tokens](https://ttoss.dev/docs/design/design-system/design-tokens) via
the `sx` prop
</Text>
</Flex>
</Box>
);
3. Custom Themes (Optional)
import type { Theme } from '@ttoss/ui';
export const customTheme: Theme = {
colors: {
primary: '#007acc',
background: '#ffffff',
text: '#000000',
},
};
Note: No custom JSX pragma needed when using sx prop directly on library components.
Chakra UI Integration
This package integrates seamlessly with Chakra UI. You can import and use any Chakra UI component directly, and it will automatically be styled according to your theme configuration.
Using Chakra UI Components
import { Button } from '@chakra-ui/react';
import { ThemeProvider } from '@ttoss/ui';
import { BruttalTheme } from '@ttoss/theme/Bruttal';
export const App = () => (
<ThemeProvider theme={BruttalTheme}>
{/* Chakra Button automatically styled with BruttalTheme */}
<Button colorScheme="blue">Chakra Button</Button>
</ThemeProvider>
);
Customizing Chakra Components via Theme
You can customize how Chakra UI components render by adding component specifications to your theme:
import type { Theme } from '@ttoss/ui';
export const customTheme: Theme = {
colors: {
primary: '#007acc',
},
// Customize Chakra UI Button component
components: {
Button: {
defaultProps: {
size: 'lg',
variant: 'solid',
},
variants: {
solid: {
bg: 'primary',
color: 'white',
},
},
},
},
};
Key Points:
- All Chakra UI components work out of the box with
ThemeProvider - Component styles are controlled through theme configuration
- No need for additional setup or wrappers
- Full access to Chakra's component theming API
Available Components
Browse all components: Storybook Documentation
Layout & Structure
Box- Basic container with styling capabilitiesFlex- Flexbox container for flexible layoutsGrid- CSS Grid container for complex layoutsContainer- Centered container with max-widthStack- Vertical/horizontal stack layoutsDivider- Visual content separatorsCard- Content containers with styling
Typography
Text- Text display with variantsHeading- Heading elements (h1-h6)Paragraph- Paragraph text blocksLink- Styled anchor elementsLabel- Form labels
Form Controls
Button- Interactive buttons with variantsActionButton- Action-specific buttonsIconButton- Icon-only buttonsCloseButton- Close/dismiss buttonsInput- Text input fields with icon supportInputNumber- Numeric input fieldsInputPassword- Password input with revealTextarea- Multi-line text inputSelect- Dropdown selectionCheckbox- Checkbox controlsRadio- Radio button controlsSwitch- Toggle switchesSlider- Range slider controlsSegmentedControl- Multi-option selector
Input Component Features
The Input component supports leading and trailing icons with tooltips:
import { Input } from '@ttoss/ui';
// Simplified syntax - icon as string
<Input
placeholder="Search..."
leadingIcon="ant-design:search-outlined"
trailingIcon="ant-design:info-circle-outlined"
/>
// Full syntax with tooltip and click handler
<Input
placeholder="Search..."
leadingIcon={{
icon: 'ant-design:search-outlined',
onClick: () => console.log('Search clicked'),
tooltip: 'Click to search'
}}
trailingIcon={{
icon: 'ant-design:info-circle-outlined',
tooltip: 'Additional information',
tooltipProps: { place: 'right' }
}}
/>
// SVG icons from @iconify
import searchIcon from '@iconify/icons-mdi/search';
<Input
placeholder="Email"
leadingIcon={searchIcon}
/>
Testing Input Icons:
Use data-testid to identify icons in tests. The Input component provides test IDs for icon containers, and each icon has its own data-testid="iconify-icon":
import { render, screen } from '@testing-library/react';
test('should render input with icons', () => {
render(
<Input placeholder="Search" leadingIcon="search" trailingIcon="info" />
);
// Get icon containers (for clicking and tooltip checks)
const leadingIconContainer = screen.getByTestId('input-leading-icon');
const trailingIconContainer = screen.getByTestId('input-trailing-icon');
expect(leadingIconContainer).toBeInTheDocument();
expect(trailingIconContainer).toBeInTheDocument();
// Get the actual icon elements (for checking icon properties)
const iconElement = leadingIconContainer.querySelector(
'[data-testid="iconify-icon"]'
);
expect(iconElement).toHaveAttribute('icon', 'search');
});
// Test icon clicks (click on container, where onClick is attached)
test('should call onClick when icon is clicked', async () => {
const handleClick = jest.fn();
render(
<Input
placeholder="Search"
leadingIcon={{ icon: 'search', onClick: handleClick }}
/>
);
const leadingIcon = screen.getByTestId('input-leading-icon');
await userEvent.click(leadingIcon);
expect(handleClick).toHaveBeenCalled();
});
// Test tooltips (check container for tooltip attributes)
test('should render tooltip', () => {
render(
<Input
placeholder="Search"
leadingIcon={{ icon: 'search', tooltip: 'Search here' }}
/>
);
const iconContainer = screen.getByTestId('input-leading-icon');
expect(iconContainer).toHaveAttribute(
'data-tooltip-id',
'input-leading-icon-tooltip'
);
});
// Alternative: Query all icons and differentiate by position
test('should render both icons using iconify-icon testid', () => {
render(<Input leadingIcon="search" trailingIcon="info" />);
const icons = screen.getAllByTestId('iconify-icon');
expect(icons).toHaveLength(2);
expect(icons[0]).toHaveAttribute('icon', 'search'); // leading
expect(icons[1]).toHaveAttribute('icon', 'info'); // trailing
});
### Feedback & Status
- `Badge` - Status indicators and labels
- `Tag` - Tagging and categorization
- `Spinner` - Loading indicators
- `LinearProgress` - Progress bars
- `InfiniteLinearProgress` - Indeterminate progress
- `Tooltip` - Contextual help text
- `HelpText` - Form help and validation text
### Media
- `Image` - Responsive image component
### Advanced Features
#### Global Styles
Theme-aware global CSS using Emotion:
```tsx
import { Global } from '@ttoss/ui';
export const AppStyles = () => (
<Global
styles={{
body: {
margin: 0,
fontFamily: 'body',
backgroundColor: 'background',
},
}}
/>
);
Animations
import { Box, keyframes } from '@ttoss/ui';
const fadeIn = keyframes({
from: { opacity: 0 },
to: { opacity: 1 },
});
export const AnimatedBox = () => (
<Box sx={{ animation: `${fadeIn} 1s ease-in` }}>Animated content</Box>
);
Theme Access
import { useTheme } from '@ttoss/ui';
export const CustomComponent = () => {
const { theme } = useTheme();
const primaryColor = theme.colors.primary;
return <div style={{ color: primaryColor }}>Themed content</div>;
};
Integration
- Design System: Part of the ttoss Design System
- Theme Integration: Uses semantic tokens
- Accessibility: Built-in WCAG compliance
- TypeScript: Full type safety with Theme UI integration
Related Packages
- @ttoss/theme: Pre-built themes (Bruttal, Oca)
- @ttoss/components: Higher-level composed components
- @ttoss/react-icons: Icon library integration