State Styling
Tosui's Box component supports state props for styling hover, focus, active, and disabled states.
State Props
Box accepts four state props that override base styles:
| Prop | Triggered By |
|---|---|
_hover | Mouse hover |
_focus | Keyboard focus |
_active | Mouse press / active |
_disabled | Disabled state |
import { Box } from "@tosui/react";
<Box
bg="surface"
p={4}
cursor="pointer"
_hover={{ bg: "primary-subtle" }}
>
Hover to highlight
</Box>
Combining States
Apply multiple state styles to a single element:
<Box
bg="surface"
p={4}
cursor="pointer"
_hover={{ bg: "primary-subtle" }}
_active={{ bg: "primary-default" }}
>
Click me
</Box>
When multiple states apply simultaneously (e.g., hover + active), they combine with later states taking precedence for conflicting properties.
Supported Properties by State
All style properties support all four states:
| Category | _hover | _focus | _active | _disabled |
|---|---|---|---|---|
Colors (color, bg, borderColor) | Yes | Yes | Yes | Yes |
Spacing (p, m, etc.) | Yes | Yes | Yes | Yes |
Sizing (w, h, etc.) | Yes | Yes | Yes | Yes |
Layout (display, position, etc.) | Yes | Yes | Yes | Yes |
Typography (fontSize, fontWeight, etc.) | Yes | Yes | Yes | Yes |
| Opacity | Yes | Yes | Yes | Yes |
| Shadow | Yes | Yes | Yes | Yes |
Interactions (cursor, pointerEvents, userSelect) | Yes | Yes | Yes | Yes |
Borders (border, borderX, borderY, etc.) | Yes | Yes | Yes | Yes |
Roundness (rounded, roundedTop, etc.) | Yes | Yes | Yes | Yes |
| Flexbox/Grid | Yes | Yes | Yes | Yes |
Text (textAlign, whiteSpace) | Yes | Yes | Yes | Yes |
Disabled State
Use _disabled to style elements when disabled:
<Box
as="button"
p={4}
bg="primary-default"
color="foreground-inverted"
cursor="pointer"
disabled
_hover={{ bg: "primary-emphasis" }}
_disabled={{
opacity: "faint",
cursor: "not-allowed",
bg: "surface"
}}
>
Submit
</Box>
The _disabled styles apply when the element has the disabled attribute or aria-disabled="true".
Responsive State Styling
State props support responsive values:
<Box
bg="surface"
p={4}
_hover={{
bg: { base: "primary-subtle", md: "primary-default" },
p: { base: 4, md: 6 }
}}
>
Different hover effect by screen size
</Box>
See the Responsive guide for more on breakpoints.
Built-in Component States
Interactive components like Button and Input have built-in state styling. You don't need to add state props—they're already styled:
// Button handles hover, active, focus, and disabled automatically
<Button>Click me</Button>
<Button disabled>Can't click</Button>
// Input handles focus and disabled automatically
<Input placeholder="Type here" />
<Input disabled placeholder="Disabled" />
Button States
Button applies these states automatically based on variant and colorScheme:
- Hover: Slightly darker/lighter background
- Active: Further emphasis
- Focus: Focus ring for accessibility
- Disabled: Reduced opacity,
not-allowedcursor
Input States
Input applies these states automatically:
- Focus: Border color change, focus ring
- Disabled: Reduced opacity, different background
When to Use State Props
Use state props for:
- Custom interactive elements built with Box
- Hover effects on cards or list items
- Custom buttons not using the Button component
Don't use state props for:
- Standard Button, Input, Link (already styled)
- Non-interactive content
- Complex hover effects (use CSS modules instead)
Examples
Hoverable Card
<Box
as="article"
p={6}
bg="surface"
rounded="md"
shadow="sm"
cursor="pointer"
_hover={{ shadow: "md", bg: "primary-subtle" }}
>
<Heading fontSize="lg">Card Title</Heading>
<Text color="foreground-muted">Card description</Text>
</Box>
Interactive List Item
<Box
p={3}
cursor="pointer"
_hover={{ bg: "surface" }}
_active={{ bg: "primary-subtle" }}
>
List item content
</Box>
Custom Button
<Box
as="button"
px={4}
py={2}
bg="primary-default"
color="foreground-inverted"
rounded="md"
cursor="pointer"
_hover={{ bg: "primary-emphasis" }}
_active={{ bg: "primary-emphasis", opacity: "high" }}
_disabled={{ opacity: "faint", cursor: "not-allowed" }}
>
Custom Button
</Box>
Focus Ring
<Box
as="button"
p={4}
bg="surface"
rounded="md"
cursor="pointer"
_focus={{ shadow: "md", borderColor: "primary-default" }}
border="thin"
borderColor="border"
>
Focusable element
</Box>
CSS Pseudo-Classes
For more complex state styling, use CSS modules with standard pseudo-classes:
/* custom.module.css */
.customButton {
transition: all 0.15s ease;
}
.customButton:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.customButton:active {
transform: translateY(0);
}
.customButton:focus-visible {
outline: 2px solid var(--t-color-primary-default);
outline-offset: 2px;
}
import styles from "./custom.module.css";
<Box className={styles.customButton} p={4} bg="surface" rounded="md">
Fancy button
</Box>
This approach is better for:
- Transitions and animations
- Transform effects
- Focus rings with outline
- Complex multi-property changes