Components
Components are ready-to-use classes generated by Shilp CSS.
Unlike utilities (which are written inside .css files), components expose
predefined class names that you can directly use in HTML.
Example:
Component classes usage<div class="container">...</div> <div class="screen-reader">...</div> <p class="limit-lines">...</p>
Components can be static or generated dynamically.
Why Components Exist
Intents and Mixins are great for writing styles inside CSS. But, sometimes you need classes that should exist automatically.
Example: .container
A container usually depends on breakpoints. If a user changes breakpoints inside
shilpConfig.theme.screens, the container component should update
automatically.
Instead of manually writing media queries, Shilp CSS generates the component. This keeps components in sync with the theme configuration.
These are reusable patterns that are easier to expose as classes.
What Is a Component?
A component is simply a regular CSS class. It is a named collection of CSS properties that can be used directly in HTML.
Example:
Base container class.container { width: 100%; margin-left: auto; margin-right: auto; padding-left: 1rem; padding-right: 1rem; }
Shilp CSS provides:
- Static components: written in CSS
- Dynamic components: generated with JavaScript
Location
There are two types of components.
1. Static Components
Defined in shilpcss/styles/components.css. These are normal CSS classes.
Example:
shilpcss/styles/components.css/* @import "./components/screen-reader.css"; */ .screen-reader { ... } .screen-reader--none { ... } /* @import "./components/limit-lines.css"; */ .limit-lines { ... }
To know more, read Components
2. Dynamic Components
Defined in shilpConfig.components. Each root-level key is a component name
and value is a component config.
Example:
const shilpConfig = { source: "react", components: { container: { ... }, }, }; export default shilpConfig;
This generates container component classes.
Where Dynamic Components Are Inserted
During processing, generated components are appended to
shilpcss/styles/components.css.
Example file structure:
shilpcss/styles/components.css/* static components */ .screen-reader { ... } .limit-lines { ... } /* import("shilpcss-dynamic-components"); */
Shilp CSS detects this exact comment string
/* import("shilpcss-dynamic-components"); */ and replaces it with generated
component classes during processing.
In other words, static and dynamic components lives in a single file.
Basic Shape of Components Config
Componet configconst componentConfig = { disable: boolean, // optional // EITHER resolve: function, // optional if generateTree exists // OR generateTree: function, // optional if resolve exists mergeTree: function, // optional if resolve exists }
You can use either resolve (function) or generateTree + mergeTree (both
are functions).
resolve
The resolve function generates component classes as a CSS string.
Dynamically generated component stringconst shilpConfig = { source: "react", extend: { components: { ipsum: { resolve: (options) => { // custom component classes generation logic return ` .any-component { @layout is-flex; max-width: theme(screens-lg); } `; }, }, }, }, }; export default shilpConfig;
You can write normal CSS, intents, mixins and inline theme functions inside the returned string.
Available Options
Custom component resolver componentConfig.resolve receives a single argument
(object) with following options:
| Option | Type | Description |
|---|---|---|
options.content | string | Raw CSS string |
options.config | object | Full shilp config object |
options.componentName | string | Mostly for error reporting |
options.componentConfig | object | Full component config |
Expected Output
The resolver must return a string containing generated CSS classes.
generateTree
Instead of returning CSS as a string, you can generate a structured tree object.
Unlike resolve, generateTree will let you modify the component tree
structure before it generates classes string.
This is useful when integrating third-party components. Know more at Merge Tree.
Dynamically generated component treeconst shilpConfig = { source: "react", extend: { components: { ipsum: { generateTree: (options) => { // Custom component generator logic return { ".ipsum": { width: "100%", "@space": "mx-auto;", "padding-left": "theme(spacing|spacing-4)", "padding-right": "theme(spacing|spacing-4)", }, }; }, }, }, }, }; export default shilpConfig;
Rules:
- Keys must be unique at the same level
- CSS properties name must use kebab-case
- Values must be
stringorobject
Writing Intents
Inside tree structure:
- Key → intent name starts with
@ - Value → utility string ending with
;
Example:
{ "@layout": "is-flex overflow-hidden shadow-lg;" }
Writing Mixins
Inside tree structure:
- Key → mixin name starts with
@ - Value → object containing styles
Example:
{ "@state hover": { "@layout": "is-flex;" } }
Writing Inline Theme Function
Inline theme works normally.
Example:
{ "max-width": "theme(screens-lg);" }
Available Options
componentConfig.generateTree receives a single argument (object) with
following options (same as resolve):
| Option | Type | Description |
|---|---|---|
options.content | string | Raw CSS string |
options.config | object | Full shilp config object |
options.componentName | string | Mostly for error reporting |
options.componentConfig | object | Full component config |
Expected Output
Must return a tree object representing CSS structure.
Shilp CSS will convert it into CSS.
mergeTree
Used together with generateTree ONLY.
It allows modifying generated component trees before converted to string.
Useful for overriding third-party component trees.
Example:
Modify dynamically generated component treeconst shilpConfig = { source: "react", extend: { components: { ipsum: { mergeTree: (options) => { // modify generated component tree // add changes only as it will be deep merged return changesOnGeneratedTree; }, }, }, }, }; export default shilpConfig;
Rules:
- Works like
shilpConfig.extend(deep merge) - Set value to
nullorundefinedto remove it from tree
Example to remove horizontal padding:
Modify dynamically generated tree before converting to stringconst componentConfig = { generateTree: () => { ... }, mergeTree: (options) => { return { ".container": { "padding-left": null, "padding-right": null, }, }; } }
Available Options
componentConfig.mergeTree receives a single argument (object) with following
options (almost same as generateTree):
| Option | Type | Description |
|---|---|---|
options.content | string | Raw CSS string |
options.config | object | Full shilp config object |
options.componentName | string | Mostly for error reporting |
options.componentConfig | object | Full component config |
options.generatedTree | object | Generated components tree structure |
Expected Output
Must return a tree object representing CSS structure.
Shilp CSS now generates actual classes string.
disable
You can disable any dynamic component. This does not affect static components or any other css classes.
For example, to disable container component:
Disable container componentconst shilpConfig = { source: "react", extend: { components: { container: { disable: true, }, }, }, }; export default shilpConfig;
This prevents Shilp CSS from generating the component entirely, and any styles defined inside it.
This can be useful when:
- Integrating third-party component classes
- Reducing bundle size
- Restricting allowed styling patterns
High-Level Components Processing
At the beginning of processing:
- Internal default mixins are created from
shilpConfig.componentsand loaded - Root-level components
shilpConfig.componentsoverride them completely (if provided)- This is not recommended. Avoid this.
shilpConfig.extend.componentsis deep merged withshilpConfig.components
This defines which components are available.
Component processing happens during build generation. There is no runtime evaluation.
See: Where Dynamic Components Are Inserted
At this stage, component processing is done.
Available Built-in Components Dataset
All built-in components datasets are documented separately.
You can explore the full list in the COMPONENTS section of the documentation.
Each dataset has its own page: /docs/components/<component-name>
Examples:
/docs/components/container/docs/components/screen-reader/docs/components/limit-lines
Those pages show exact components dataset structure with usage example.