Skip to main content

@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 capabilities
  • Flex - Flexbox container for flexible layouts
  • Grid - CSS Grid container for complex layouts
  • Container - Centered container with max-width
  • Stack - Vertical/horizontal stack layouts
  • Divider - Visual content separators
  • Card - Content containers with styling

Typography

  • Text - Text display with variants
  • Heading - Heading elements (h1-h6)
  • Paragraph - Paragraph text blocks
  • Link - Styled anchor elements
  • Label - Form labels

Form Controls

  • Button - Interactive buttons with variants
  • ActionButton - Action-specific buttons
  • IconButton - Icon-only buttons
  • CloseButton - Close/dismiss buttons
  • Input - Text input fields with icon support
  • InputNumber - Numeric input fields
  • InputPassword - Password input with reveal
  • Textarea - Multi-line text input
  • Select - Dropdown selection
  • Checkbox - Checkbox controls
  • Radio - Radio button controls
  • Switch - Toggle switches
  • Slider - Range slider controls
  • SegmentedControl - 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