Composition
Composable components built on Base UI primitives that you can use whole or extend with your own styles.
Built on Base UI
Compose UI components are built on top of Base UI primitives. Base UI provides the behavioral foundation—state management, keyboard interactions, ARIA attributes—while Compose UI adds the styling layer with Tailwind CSS.
This means you get components that are both ready to use out of the box and easy to customize when you need something different.
Using Components As-Is
The simplest approach is to use components directly:
import { Button } from '@lglab/compose-ui'
function MyComponent() {
return <Button variant='outline'>Click me</Button>
}Components come with sensible defaults and multiple variants to cover common use cases.
Extending with className
All components accept a className prop that merges with the default styles using tailwind-merge. This lets you add or override styles without fighting specificity:
<Button className='w-full'>Full Width Button</Button><DialogContent className='max-w-2xl'>{/* Wider dialog */}</DialogContent>Compound Components
Compose UI components use the compound component pattern, giving you control over structure while maintaining proper behavior:
import { TabsIndicator, TabsList, TabsPanel, TabsRoot, TabsTab } from '@lglab/compose-ui'
export function Tabs() {
return (
<TabsRoot defaultValue='one'>
<TabsList>
<TabsTab value='one'>First</TabsTab>
<TabsTab value='two'>Second</TabsTab>
<TabsIndicator />
</TabsList>
<TabsPanel value='one'>Content one</TabsPanel>
<TabsPanel value='two'>Content two</TabsPanel>
</TabsRoot>
)
}You can rearrange, wrap, or style individual parts as needed. Each sub-component is a separate export, so you only import what you use.
Wrapping Components
For repeated customizations, wrap components to create your own variants:
import { Button, type ButtonProps } from '@lglab/compose-ui'
function IconButton({ children, ...props }: ButtonProps) {
return (
<Button size='icon' variant='ghost' {...props}>
{children}
</Button>
)
}