properties
changelog

Utilities

A utility is the smallest styling word inside an intent.

If intent defines where something belongs, utility defines what exactly to apply.


What Happens After Intent Is Found

From the Intents Config Page we know that, Shilp CSS extracts intent-name and list of utilities.

Example:

style.css
.any-class {
	@layout is-flex overflow-y-auto;
	@text color-orange-600 thick-600;
}

Here:

  1. Layout intent
    • Intent name: layout
    • Utilities: is-flex, overflow-y-auto
  2. Text intent
    • Intent name: text
    • Utilities: color-orange-600, thick-600

It processes each utility individually and each utility becomes a real CSS rule.

Utility Object

For every utility, Shilp CSS creates a utility object with it's information.

For example, intent @space -ml-1/2!; is splits into the two parts:

  • Intent name: space
  • Utilities: -ml-1/2!

Utility further splits into:

  • raw: -ml-1/2!
  • value: ml-1/2
  • negative: true
  • variant: undefined
  • important: true

Let’s understand each part.

raw

At first, the entire string is stored as it is. The raw value is kept mainly for error reporting.

Now utility object becomes:

const utility = {
	raw: "-ml-1/2!",
};

value

At first, it will be same as raw string. later while extracting other parts, it will be updated.

Now utility object becomes:

const utility = {
	raw: "-ml-1/2!",
	value: "-ml-1/2!",
};

negative

If the utility starts with -, it means negative value.

Now utility object becomes:

const utility = {
	raw: "-ml-1/2!",
	value: "ml-1/2!",
	negative: true,
};

Example:

  • @space ml-1/2; → margin-left: 50%;
  • @space -ml-1/2; → margin-left: -50%;

important

If utility ends with !, it means !important.

Now utility object becomes:

const utility = {
	raw: "-ml-1/2!",
	value: "ml-1/2",
	negative: true,
	important: true,
};

Example:

  • @space ml-1/2; → margin-left: 50%;
  • @space ml-1/2!; → margin-left: 50% !important;

variant

If utility includes /, the first slash defines a variant.

For example @text color-orange-600/80; splits into:

  • Value: "color-orange-600" → color
  • Variant:"80" → opacity

For our example @space -ml-1/2!;, now utility object becomes:

const utility = {
	raw: "-ml-1/2!",
	value: "ml-1/2",
	negative: true,
	important: true,
	variant: undefined,
};

Important Behaviouor

Variant behavior only works, if the Properties Config explicitly enables it.

If not enabled:
Then /2 in @space -ml-1/2!; is part of the utility value (fraction), not a variant.

If enabled:
Then only the first / is considered. Any slash / after the first one is ignored.

UtilityVariant
color-orange-600/80"80"
color-orange-600/80/lorem/ipsum"80"

Now, this will output color: oklch(64.6% 0.222 41.116 / 0.8);.

Tokens

After raw utility splits and utility object is created, the utility.value is further split by -. This is called tokens.

UtilityTokens
ml-1/2["ml", "1/2"]
color-orange-600["color", "orange", "600"]

These tokens are used to traverse the property configuration.

Property Tokens vs Value Tokens

From shilpConfig.properties[intentName], Shilp CSS Algorithm walks through nested objects using tokens.

While traversing nested objects, if it reach to an object, which has property key, then this object is called property config.

Tokens used to reach property config is called as Property Tokens and the remaining tokens are called Value Tokens.

For ml-1/2:

Token TypeTokens
Property["ml"]
Value["1/2"]

For color-orange-600:

Token TypeTokens
Property["color"]
Value["orange", "600"]

For overflow-x-auto:

Token TypeTokens
Property["overflow", "x"]
Value["auto"]

At this point, we know the exact css property for the particular utility.

Role of DEFAULT Key

If a token is not found at current level, Shilp CSS first checks for DEFAULT key.

Example config:

shilp.config.js
const shilpConfig = {
	source: "react",

	properties: {
		//
		layout: {
			//
			overflow: {
				//
				DEFAULT: {
					property: "overflow: <v><i>;",
					values: {
						auto: "auto",
						hidden: "hidden",
						// other values
					},
				},

				x: {
					property: "overflow-x: <v><i>;",
					values: {
						// same values as oveflow.DEFAULT
					},
				},

				y: {
					property: "overflow-y: <v><i>;",
					values: {
						// same values as oveflow.DEFAULT
					},
				},
			},
		},
	},
};

export default shilpConfig;

This enables:

  • @layout overflow-hidden;overflow: hidden;
  • @layout overflow-y-auto;overflow-y: auto;

Instead of:

  • @layout overflow-DEFAULT-hidden;overflow: hidden;

It lets you skip that extra token, while keeping structure flexible inside config. you don’t need to write -DEFAULT.

When Errors Happen

An error is thrown, if property config or property values not found with tokens.

High-Level Utilities Processing

Unlike shilpConfig.intents, utilities do not have their own config key.

There is no shilpConfig.utilities. They are purely derived from shilpConfig.properties.

Every utility exists because:

  1. An intent exists
  2. A property exists under that intent
  3. Values are defined for that property

Now, at this point we have:

  • Intent name
  • Property config
  • Value tokens
  • Negative flag
  • Important flag
  • Variant (if enabled and also exist in utility)

At this stage, utility processing is done.

Further processing is handled by the Properties.