properties
changelog

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 config
const 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 string
const 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:

OptionTypeDescription
options.contentstringRaw CSS string
options.configobjectFull shilp config object
options.componentNamestringMostly for error reporting
options.componentConfigobjectFull 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 tree
const 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 string or object

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):

OptionTypeDescription
options.contentstringRaw CSS string
options.configobjectFull shilp config object
options.componentNamestringMostly for error reporting
options.componentConfigobjectFull 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 tree
const 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 null or undefined to remove it from tree

Example to remove horizontal padding:

Modify dynamically generated tree before converting to string
const 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):

OptionTypeDescription
options.contentstringRaw CSS string
options.configobjectFull shilp config object
options.componentNamestringMostly for error reporting
options.componentConfigobjectFull component config
options.generatedTreeobjectGenerated 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 component
const 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.components and loaded
  • Root-level components shilpConfig.components override them completely (if provided)
    • This is not recommended. Avoid this.
  • shilpConfig.extend.components is deep merged with shilpConfig.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.