Design Approach

How Selia components are designed to work together.

Selia strives for visual cohesion. Components are meant to work beautifully together right out of the box, with minimal configuration required.

We achieve this through two key mechanisms:

1. Plain Variant

Some components include a plain variant that strips away visual styling like backgrounds, borders, and shadows. This allows them to be seamlessly nested inside other components without visual conflicts.

The plain variant can mean different things depending on the component. In Button, plain removes the background color in its normal state while adding visual emphasis on hover. However, in components like InputGroup, plain is primarily intended for composition—stripping away styling so it can be nested within other components, as we do with Command.

2. Contextual Styling

Parent components apply contextual styling to their children via data-slot attributes. This ensures composed components look cohesive without manual styling.

selia/command.tsx

Not all components require the plain variant for composition. For example, the Input component within InputGroup automatically has its background, shadow, and border removed—because in this context, Input is already part of InputGroup's control structure.

Why This Approach?

We expect certain components to be frequently composed together. Rather than requiring you to add styling manually each time, we handle it by default.

Common Composition Patterns

Here are some common examples:


Command with InputGroup:

InputGroup in Command

Here, variant="plain" removes InputGroup's default styling, while Command applies its own contextual styling (height, padding) to match its design.


Table in Card:

TableContainer in Card Body

The CardBody component applies negative margins to TableContainer children, creating a clean edge-to-edge layout without the table being cramped by the card's padding.


Item in Menu:

Item as MenuRadioItem

The Item component adapts its styling when used inside Menu, maintaining consistent padding and hover states.

Styling Trade-offs

While contextual styling makes composition seamless, it relies on high-specificity CSS selectors (like [&_[data-slot=...]]). This approach comes with a small trade-off you should keep in mind.

Overriding Contextual Styles

When a parent component "forces" a style on a child (e.g., the Sidebar setting the height of its buttons), a standard Tailwind class on the child might not always win the specificity battle.

If you need to override a contextually applied style for a one-off edge case, you have two clear paths:

  • The Escape Hatch: Use the ! (important) modifier (e.g., p-4! rounded-full!). This is the intended way to handle rare exceptions without over-engineering the component's logic.
  • Global Refinement: If you find yourself overriding the same style repeatedly, it’s a sign that the design system should be adjusted. Since Selia lives in your codebase, we recommend modifying the component source directly to maintain global consistency.

We prioritize a clean, predictable default experience over complex prop-drilling or context-heavy logic just to avoid occasional CSS priority conflicts.