Styling
Style HeroUI components with CSS, Tailwind, or CSS-in-JS
Overview
HeroUI components are built on React Aria and provide flexible styling options:
- Tailwind CSS - Use utility classes directly
- CSS - Target BEM classes or data attributes
- CSS-in-JS - Integrate with styled-components, Emotion, etc.
- Render props - Dynamic styling based on component state
Basic Styling
Using className
All HeroUI components accept className
props:
<Button className="bg-purple-500 hover:bg-purple-600">
Custom Button
</Button>
<Accordion className="border-2 border-gray-200 rounded-xl">
{/* content */}
</Accordion>
Using style
Components also accept inline styles:
<Button style={{ backgroundColor: '#8B5CF6' }}>
Styled Button
</Button>
State-Based Styling
HeroUI components expose their state through data attributes, similar to CSS pseudo-classes:
/* Target different states */
.button[data-hover="true"], .button:hover {
background: var(--accent-hover);
}
.button[data-pressed="true"], .button:active {
transform: scale(0.97);
}
.button[data-focus-visible="true"], .button:focus-visible {
outline: 2px solid var(--focus);
}
Render Props
Use render props for dynamic styling based on component state:
// Dynamic classes
<Button
className={({ isPressed }) =>
isPressed ? 'bg-blue-600' : 'bg-blue-500'
}
>
Press me
</Button>
// Dynamic content
<Button>
{({ isHovered, isPressed }) => (
<>
<Icon
icon="gravity-ui:heart"
className={isPressed ? 'text-red-500' : 'text-neutral-400'}
/>
<span className={isHovered ? 'underline' : ''}>
Like
</span>
</>
)}
</Button>
BEM Classes
HeroUI uses BEM methodology for consistent class naming:
/* Block */
.button { }
.accordion { }
/* Element */
.accordion__trigger { }
.accordion__panel { }
/* Modifier */
.button--primary { }
.button--lg { }
.accordion--outline { }
Customizing Components Globally
/* global.css */
@layer components {
/* Override button styles */
.button {
@apply font-semibold uppercase;
}
.button--primary {
@apply bg-indigo-600 hover:bg-indigo-700;
}
/* Add custom variant */
.button--gradient {
@apply bg-gradient-to-r from-purple-500 to-pink-500;
}
}
Creating Wrapper Components
For reusable custom components, create wrappers using tailwind-variants - a Tailwind CSS first-class variant API created by us as well:
import { Button as HeroButton, buttonVariants, type ButtonProps } from '@heroui/react';
import { tv, type VariantProps } from 'tailwind-variants';
const customButtonVariants = tv({
extend: buttonVariants,
base: 'font-medium transition-all',
variants: {
intent: {
primary: 'bg-blue-500 hover:bg-blue-600 text-white',
secondary: 'bg-gray-200 hover:bg-gray-300',
danger: 'bg-red-500 hover:bg-red-600 text-white',
},
size: {
small: 'text-sm px-2 py-1',
medium: 'text-base px-4 py-2',
large: 'text-lg px-6 py-3',
},
},
defaultVariants: {
intent: 'primary',
size: 'medium',
},
});
type CustomButtonVariants = VariantProps<typeof customButtonVariants>;
interface CustomButtonProps
extends Omit<ButtonProps, 'className'>,
CustomButtonVariants {
className?: string;
}
export function CustomButton({ intent, size, className, ...props }: CustomButtonProps) {
return (
<HeroButton
className={customButtonVariants({ intent, size, className })}
{...props}
/>
);
}
CSS-in-JS Integration
Styled Components
import styled from 'styled-components';
import { Button } from '@heroui/react';
const StyledButton = styled(Button)`
background: linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%);
border-radius: 8px;
color: white;
padding: 12px 24px;
&:hover {
box-shadow: 0 3px 10px rgba(255, 105, 135, 0.3);
}
`;
Emotion
import { css } from '@emotion/css';
import { Button } from '@heroui/react';
const buttonStyles = css`
background: linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%);
border-radius: 8px;
color: white;
padding: 12px 24px;
&:hover {
box-shadow: 0 3px 10px rgba(255, 105, 135, 0.3);
}
`;
<Button className={buttonStyles}>
Emotion Button
</Button>
Responsive Design
Use Tailwind's responsive utilities:
<Button className="text-sm md:text-base lg:text-lg px-3 md:px-4 lg:px-6">
Responsive Button
</Button>
Or with CSS:
.button {
font-size: 0.875rem;
padding: 0.5rem 1rem;
}
@media (min-width: 768px) {
.button {
font-size: 1rem;
padding: 0.75rem 1.5rem;
}
}
CSS Modules
For scoped styles, use CSS Modules:
/* Button.module.css */
.button {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
padding: 12px 24px;
border-radius: 8px;
}
.button:hover {
transform: translateY(-2px);
}
.button--primary {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
padding: 12px 24px;
border-radius: 8px;
}
import styles from './Button.module.css';
import { Button } from '@heroui/react';
<Button className={styles.button}>
Scoped Button
</Button>
Component Classes Reference
Button
.button
- Base.button--{variant}
- Variants.button--{size}
- Sizes.button--icon-only
- Icon button
Note: See Button for more information on button classes.
Accordion
.accordion
- Container.accordion__item
- Item.accordion__trigger
- Header.accordion__panel
- Content.accordion--outline
- Variant
Note: See Accordion for more information on accordion classes.
View all component classes in @heroui/styles/components.