Styling With Intent
With Shilp CSS, you don’t build styles by accumulating utilities in HTML, You compose them in CSS by clearly stating what an element is responsible for.
Thinking in Responsibilities
When styling an element, think in terms of intent:
- How it look like?
- How does space behave?
- How should text appear?
- What colors does it use?
- How does it react to state or context?
Each of these answers belongs to a separate intent.
Intent
Shilp CSS groups styling concerns explicitly by intent.
Each intent exists to hold one kind of a decision.
| Intent | Purpose | Utilities |
|---|---|---|
@bg | Background styles | color, gradient, image, etc |
@text | Typography styles | size, weight, color, alignment, etc |
@layout | Layout styles | display, layer, overflow, shadow, etc |
@flex | Flex styles | align, justify, grow, shrink, etc |
@space | Spacing styles | padding, margin and gap |
@border | Border styles | color, radius, thickness, etc |
@animate | Animation styles | enter, exit, delay, duration, etc |
and it goes on...
Example
Using intent to build component.card { @bg color-surface; @text color-surface-fg; @layout is-flex shadow-sm shadow-color-fg/5; @flex flow-col; @border thick rounded-xl; @space py-6 gap-6; }
Each intent exists to hold a single responsibility.
Stateful Intents (Mixins)
Stateful intents applies styles only when certain conditions are met.
These are implemented as mixins and can:
- coexist with regular and other stateful intents
- nest within each other
- changes scope clearly
| Directive | Purpose | Variants |
|---|---|---|
@state | UI states | hover, focus, disabled |
@theme | Theme variations | dark, light |
@childs | Child selectors | first, last, any, direct |
@screen | Responsive breakpoints | sm, md, xl |
and it goes on...
Example
Using stateful intent (mixins) to build component.card { /* Regular intents */ @bg color-surface; @text color-surface-fg; @layout is-flex shadow-sm shadow-color-fg/5; @flex flow-col; @border thick rounded-xl; @space py-6 gap-6; /* Stateful intents ( responsive + state ) */ @screen xl { @space py-8 gap-10; @state hover { @border thick-2; } } /* Stateful intents ( theme ) */ @theme dark { @bg color-surface/90; @text color-surface-fg/90; } }
Each intent still holds one kind of a decision.
No mixing. No Guessing.
Using Arbitrary Values or Custom CSS
Shilp CSS does not invent a special syntax for everything. If something does not fit an intent, mixin or an utility, use plain CSS.
Intent-based styling is a tool, not a cage.
You can freely write:
Using custom CSS to build a component.card { /* Regular intents */ @text color-surface-fg; /* Plain CSS */ background-image: linear-gradient( in oklch to top right, cyan 20%, magenta 50%, yellow 70%, black 100% ); /* Stateful intents ( theme ) */ @theme dark { @bg color-surface/90; @text color-surface-fg/90; } }
Using Theme Values Inline
You can reference theme values directly in custom CSS using inline theme(...)
function. You can use it anywhere a value is expected.
Using inline theme value for custom CSS.any-class { background-image: linear-gradient( in oklch to theme(angles-45), oklch(theme(colors-html-cyan)) theme(spacing-1/5), oklch(theme(colors-html-magenta) / 0.9) theme(spacing-1/2), oklch(theme(colors-orange-600)) 70%, oklch(theme(colors-black)) theme(spacing-full) ); }
This keeps custom CSS aligned with the system without forcing everything through intent and utilities.
See: Inline Theme Function.
Using The Important Flag
Shilp CSS has !important flag implementation. It can be applied to intent and
utilities, but not on mixins.
Add ! just after utility or intent name.
Using the important flag.card { /* on one utility */ @layout is-flex! shadow-sm; /* on all utilities */ @layout is-flex! shadow-sm!; /* on all utilities but via intent name */ @layout! is-flex shadow-sm; }
This works. But, it should be rare.
Use it only when:
- Overriding third-party CSS
- Debugging
Conflicting Intent or Utilities
When multiple declarations apply, the rule with higher specificity
wins.
For simplicity, ASSUME the last declration wins.
This follows normal CSS behavior. Shilp CSS does not add conflict resolution logic on top.
Because intent is grouped, conflicts are usually obvious and easy to fix.
If you are unsure which rule applies, check the browser’s DevTool.
Why This Scales Better?
When intent is grouped:
- Layout refactors don’t touch text rules
- Changes don’t require markup edits
- Shared patterns are obvious and named
- The affected area is predictable
This is what makes large systems calm to maintain.
Is Shilp CSS Anti-Utility?
A big NO.
Utilities still exist. But, they are config-driven, reusable and composable.
The difference is where composition happens.
| Approach | Composition |
|---|---|
| Utility-first atomic classes | in markup |
| Shilp CSS | in CSS |
Shilp CSS keeps Intent and Utility-first idea both, and makes sure they live where they belong.
Same power. Different ownership model.
What You Intentionally Avoid
Styling with intent means you avoid:
- Encoding meaning through loooong string of classes
- Mixing unrelated concerns in one place
- Relying on conventions to imply structure
- Refactoring by hunting class strings
Intent is explicit by construction.
The Outcome
Styling with intent gives you:
- Clear ownership of styles
- Readable, navigable stylesheets
- Semantic and smaller markup
- Refactors that feel controlled
This is not about writing more CSS. It’s about writing CSS that explains itself.
Reserved Names
CSS at-rules:
@charset@import@namespace@media@supports@layer@scope@container@page@font-face@font-feature-values@keyframes@counter-style@property@color-profile@view-transition@starting-style
SCSS at-rules:
@use@forward@import@mixin@include@function@return@if@else@each@for@while@error@warn@debug@at-root@extend@content