Conditional Styles
Learn how to apply conditional styles in Cerberus Design System
Overview
Cerberus allows you to write styles for pseudo states, media queries, and custom data attributes with the conditional style props.
Usage
For example, here's how to change the background color of a button when it's hovered:
1<Box bg="danger.bg.initial" _hover={{ bg: "danger.bg.hover" }}>2 Hover me3</Box>
Nested condition
Conditional values can be nested to create complex selector rules.
Here's how to change the background color of an element when in focus on hover:
1<Box bg={{ base: "danger.bg.initial", _hover: { _focus: "danger.bg.hover" } }}>2 Hover & Focus me3</Box>
At Rules
This also works with the supported at-rules (@media
, @layer
, @container
,
@supports
, and @page
):
1<Box2 css={{3 "@container (min-width: 10px)": {4 color: "success.surface.initial",5 },6 }}7>8 Hello9</Box>
Pseudo Classes
Hover, Active, Focus, and Disabled
Here's an example of how to style the hover, active, focus, and disabled states of an element
1<Box2 _hover={{ bg: "danger.bg.hover" }}3 _active={{ bg: "danger.bg.active" }}4 _focus={{ bg: "danger.bg.initial" }}5 _disabled={{ opacity: "0.5" }}6>7 Hover me > Hover me8</Box>
First, Last, Odd, Even
Here's an example of how to style the first, last, odd, and even elements in a list
1<ul>2 <For each={items}>3 {(item) => (4 <li key={item}>5 <Box6 _first={{ color: "danger.bg.initial" }}7 _last={{ color: "red.800" }}8 >9 {item}10 </Box>11 </li>12 )}13 </For>14</ul>
You can also style even and odd elements using the _even
and _odd
modifier
1<Table.Root>2 <Table.Body>3 <For each={items}>4 {(item) => (5 <Table.Row key={item} css={{6 _even={{ bg: "gray.100" }}7 _odd={{ bg: "white" }}8 }}>9 <Table.Cell>{item}</Table.Cell>10 </Table.Row>11 )}12 </Table.Body>13</Table.Root>
Pseudo Elements
Before and After
To style the ::before
and ::after
pseudo elements of an element, use the
_before
and _after
modifiers
1<Box _before={{ content: '"👋"' }} _after={{ content: '"🥂"' }}>2 Hello3</Box>
Placeholder
To style the placeholder text of any input or textarea, use the _placeholder
modifier:
1<Input2 placeholder="Enter your name"3 css={{4 _placeholder={{ color: "gray.500" }}5 }}6/>
File Inputs
To style the file input button, use the _file
modifier:
1<Input2 type="file"3 css={{4 _file={{ bg: "gray.500", px: "4", py: "2", marginEnd: "3" }}5 }}6/>
Media Queries
Reduced Motion
Use the _motionReduce
and _motionSafe
modifiers to style an element based on
the user's motion preference:
1<Box _motionSafe={{ transition: "all 0.3s" }}>Hello</Box>
Color Scheme
The prefers-color-scheme
media feature is used to detect if the user has
requested the system to use a light or dark color theme.
Use the _osLight
and _osDark
modifiers to style an element based on the
user's color scheme preference:
1<Box bg={{ base: "white", _osDark: "black" }}>Hello</Box>
Color Contrast
The prefers-contrast
media feature is used to detect if the user has requested
the system use a high or low contrast theme.
Use the _highContrast
and _lessContrast
modifiers to style an element based
on the user's color contrast preference:
1<Box bg={{ base: "white", _highContrast: "black" }}>Hello</Box>
Orientation
The orientation
media feature is used to detect if the user has a device in
portrait or landscape mode.
Use the _portrait
and _landscape
modifiers to style an element based on the
user's device orientation:
1<Box pb="4" _portrait={{ pb: "8" }}>2 Hello3</Box>
Selectors
Arbitrary selectors
For arbitrary, use the css
prop to write styles for one-off selectors:
1<Box css={{ "&[data-state=closed]": { color: "red.300" } }} />
Here's another example that targets the child elements of a parent element:
1<Box2 css={{3 "& > *": { margin: "2" },4 }}5/>
Group Selectors
To style an element based on its parent element's state or attribute, add the
group
class to the parent element, and use any of the _group*
modifiers on
the child element.
1<div className="group">2 <Text _groupHover={{ bg: "danger.bg.initial" }}>Hover me</Text>3</div>
This modifier works for every pseudo class modifiers like _groupHover
,
_groupActive
, _groupFocus
, and _groupDisabled
, etc.
Sibling Selectors
To style an element based on its sibling element's state or attribute, add the
peer
class to the sibling element, and use any of the _peer*
modifiers on
the target element.
1<div>2 <p className="peer">Hover me</p>3 <Box _peerHover={{ bg: "danger.bg.initial" }}>I'll change by bg</Box>4</div>
Note: This only works for when the element marked with
peer
is a previous siblings, that is, it comes before the element you want to start.
Data Attribute
LTR and RTL
To style an element based on the direction of the text, use the _ltr
and
_rtl
modifiers
1<div dir="ltr">2 <Box _ltr={{ ml: "3" }} _rtl={{ mr: "3" }}>3 Hello4 </Box>5</div>
State
To style an element based on its data-{state}
attribute, use the corresponding
_{state}
modifier
1<Box data-state="indeterminate" _indeterminate={{ bg: "gray.500" }}>2 Hello3</Box>
This works for common states like data-active
, data-disabled
, data-focus
,
data-hover
, data-invalid
, data-required
, and data-valid
.
1<Box data-active _active={{ bg: "gray.500" }}>2 Hello3</Box>
Orientation
To style an element based on its data-orientation
attribute, use the
_horizontal
and _vertical
modifiers
1<Box2 data-orientation="horizontal"3 _horizontal={{ bg: "danger.bg.initial" }}4 _vertical={{ bg: "action.bg.initial" }}5>6 Hello7</Box>
ARIA Attribute
To style an element based on its aria-{state}=true
attribute, use the
corresponding _{state}
prop
1<Box aria-expanded="true" _expanded={{ bg: "gray.500" }}>2 Hello3</Box>
Reference
Here's a list of all the condition props you can use in Cerberus:
Cerberus extends the built-in conditions provided by Panda-CSS.
Name | Selector |
---|---|
_cerberusTheme | [data-theme=cerberus] & |
_acheronTheme | [data-theme=acheron] & |
_lightMode | [data-color-mode=light] &, &.light, .light & |
_darkMode | [data-color-mode=dark] &, &.dark, .dark & |
_open | '&:is([open], [data-open], [data-state=open])' |
_closed | '&:is([closed], [data-closed], [data-state=closed])' |
_notDisabled | &:is(:not([disabled]), [data-disabled=false]) |
_modalOpen | &:is([data-modal-open=true]) |
_screenReaderOnly | &:is([data-screen-reader-only=true]) |
_isOver | &:is([data-over=true]) |
_isDropped | &:is([data-dropped=true]) |
_today | &:is([data-today=true], [data-date=today]) |
_pastDay | &:is([data-past-day=true], [data-date=past]) |
_inRange | &:is([data-in-range=true]) |
_startRange | &:is([data-start-range]) |
_endRange | &:is([data-end-range]) |
_invalid | &:is(:invalid, [data-invalid], [aria-invalid]) |
_userInvalid | &:is(:user-invalid, [aria-invalid]) |
_groupInvalid | .group:is([data-invalid] &, [aria-invalid]) & |
_groupChecked | .group:is([data-checked="true"] &, [aria-checked="true"]) & |
_positionBottom | &:is([data-position=bottom]) |
_positionTop | &:is([data-position=top]) |
_positionLeft | &:is([data-position=left]) |
_positionRight | &:is([data-position=right]) |
_startIcon | &:is([data-start-icon=true]) |
_tooltip | &:is([data-tooltip=true]) |
_notify | &:is([data-notify=true]) |
_admin | &:is([data-role=admin]) |
_student | &:is([data-role=student]) |
_user | &:is([data-role=user]) |
_highlight | &:is(::selection) |
_spellingError | &:is(::spelling-error) |
_grammarError | &:is(::grammar-error) |
_pagePalette | &:is([data-palette=page]) |
_actionPalette | &:is([data-palette=action]) |
_infoPalette | &:is([data-palette=info]) |
_successPalette | &:is([data-palette=success]) |
_warningPalette | &:is([data-palette=warning]) |
_dangerPalette | &:is([data-palette=danger]) |
Customization
Cerberus lets you create your own conditions, so you're not limited to the ones in the default preset. Learn more about customizing conditions here.
On this page