Skip to content

Shortcuts

The core:shortcuts plugin enables reusable style combinations. Define named style shortcuts and reference them as string style items passed to pika() or via the __shortcut property inside style definitions.

How It Works

  1. Shortcut definitions are collected from config.shortcuts.shortcuts during rawConfigConfigured.
  2. During configureEngine, each definition is resolved and registered:
    • Static rules are stored for exact-match lookup.
    • Dynamic rules are stored for RegExp-based matching.
    • Autocomplete entries are added for known shortcuts.
  3. The plugin operates on two hooks:
    • transformStyleItems — string style items are checked against the ShortcutResolver. If matched, the resolved items replace the original string.
    • transformStyleDefinitions — when a style definition contains a __shortcut property, the shortcut is resolved and the resulting style definitions are inserted before the remaining properties of the current definition.
  4. Unmatched shortcut strings are returned unchanged (passed through as-is).

Config

ts
interface ShortcutsConfig {
  /** Array of shortcut definitions. @default [] */
  shortcuts: Shortcut[]
}

Shortcut Definition Formats

There are 5 forms for defining shortcuts: 1 string form, 2 tuple forms, and 2 object forms.

String Form

A plain string is registered as an autocomplete suggestion only — no resolution rule is created.

ts
// String form: autocomplete-only, no resolution rule
const shortcut = 'flex-center'

Tuple Form — Static

ts
type TupleFormStatic = [shortcut: string, value: Arrayable<ResolvedStyleItem>]

The value can be a StyleDefinition object, a string referencing another shortcut, or an array of both:

ts
// Tuple form — static: [name, value]
// value can be a StyleDefinition, a string (another shortcut), or an array of both
const shortcuts = [
	// Single style definition
	['flex-center', {
		display: 'flex',
		alignItems: 'center',
		justifyContent: 'center',
	}],

	// Multiple style items (array of StyleDefinitions)
	['btn-base', [
		{ padding: '0.5rem 1rem', borderRadius: '0.25rem', cursor: 'pointer' },
		{ border: 'none', fontSize: '1rem' },
	]],

	// Reference another shortcut by name (string value)
	['centered', 'flex-center'],
]

Tuple Form — Dynamic

ts
type TupleFormDynamic = [shortcut: RegExp, value: (matched: RegExpMatchArray) => Awaitable<Arrayable<ResolvedStyleItem>>, autocomplete?: Arrayable<string>]

The resolver function receives the RegExpMatchArray from the pattern match and returns one or more ResolvedStyleItems. Optional autocomplete hints provide IDE suggestions for the dynamic pattern:

ts
// Tuple form — dynamic: [pattern, resolver, autocomplete?]
// The resolver receives RegExpMatchArray and returns ResolvedStyleItem(s)
const shortcuts = [
	// Dynamic margin shortcut
	[
		/^m-(\d+)$/,
		(m: RegExpMatchArray) => ({ margin: `${Number(m[1]) * 0.25}rem` }),
		['m-1', 'm-2', 'm-4', 'm-8'], // autocomplete hints
	],

	// Dynamic size shortcut returning a single definition
	[
		/^size-(\d+)$/,
		(m: RegExpMatchArray) => ({
			width: `${m[1]}px`,
			height: `${m[1]}px`,
		}),
		['size-16', 'size-24', 'size-32'],
	],

	// Dynamic shortcut returning multiple style items
	[
		/^card-(\w+)$/,
		(m: RegExpMatchArray) => [
			{ padding: '1rem', borderRadius: '0.5rem' },
			{ backgroundColor: m[1] },
		],
	],
]

Object Form

Equivalent to tuple forms but with named properties. Both static and dynamic variants are supported:

ts
// Object form — equivalent to tuple forms but with named properties
const shortcuts = [
	// Object form — static
	{
		shortcut: 'flex-center',
		value: {
			display: 'flex',
			alignItems: 'center',
			justifyContent: 'center',
		},
	},

	// Object form — dynamic
	{
		shortcut: /^p-(\d+)$/,
		value: (m: RegExpMatchArray) => ({
			padding: `${Number(m[1]) * 0.25}rem`,
		}),
		autocomplete: ['p-1', 'p-2', 'p-4'],
	},
]

Full Example

ts
// pika.config.ts
import { defineEngineConfig } from '@pikacss/unplugin-pikacss'

export default defineEngineConfig({
	shortcuts: {
		shortcuts: [
			// String form: autocomplete-only
			'my-custom-shortcut',

			// Tuple form — static
			['flex-center', {
				display: 'flex',
				alignItems: 'center',
				justifyContent: 'center',
			}],

			// Tuple form — static with multiple style items
			['btn', [
				{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center' },
				{ padding: '0.5rem 1rem', borderRadius: '0.25rem' },
				{ border: 'none', cursor: 'pointer', fontSize: '1rem' },
			]],

			// Tuple form — dynamic
			[
				/^m-(\d+)$/,
				m => ({ margin: `${Number(m[1]) * 0.25}rem` }),
				['m-1', 'm-2', 'm-4', 'm-8'],
			],

			// Object form — static
			{
				shortcut: 'sr-only',
				value: {
					position: 'absolute',
					width: '1px',
					height: '1px',
					padding: '0',
					margin: '-1px',
					overflow: 'hidden',
					clip: 'rect(0, 0, 0, 0)',
					whiteSpace: 'nowrap',
					borderWidth: '0',
				},
			},

			// Object form — dynamic
			{
				shortcut: /^size-(\d+)$/,
				value: m => ({ width: `${m[1]}px`, height: `${m[1]}px` }),
				autocomplete: ['size-16', 'size-24', 'size-32'],
			},
		],
	},
})

Usage with pika()

Shortcuts can be used in two ways:

As String Arguments

Pass shortcut names as string arguments to pika(). They are resolved alongside other style items:

ts
// Use a shortcut as a string argument to pika()
// Shortcuts resolve to their underlying style items at build time

// Single shortcut
const centered = pika('flex-center')

// Shortcut mixed with inline style definitions
const card = pika(
	'flex-center',
	{ gap: '1rem', padding: '2rem' },
)

// Dynamic shortcut as string argument
const spaced = pika('m-4', { color: 'blue' })

Generated CSS output:

css
/* pika('flex-center', { gap: '1rem', padding: '2rem' }) */
.a { display: flex; }
.b { align-items: center; }
.c { justify-content: center; }
.d { gap: 1rem; }
.e { padding: 2rem; }

The __shortcut Property

Use __shortcut inside a style definition to apply one or more shortcuts. The resolved styles are merged before any other properties in the definition:

ts
// Use __shortcut property in a style definition
// Shortcut styles are inserted BEFORE other properties in the definition

// Single shortcut via __shortcut
const centered = pika({
	__shortcut: 'flex-center',
	gap: '1rem',
})

// Multiple shortcuts via __shortcut array
const button = pika({
	__shortcut: ['flex-center', 'btn'],
	backgroundColor: '#0ea5e9',
	color: 'white',
})

// Dynamic shortcut via __shortcut
const spacing = pika({
	__shortcut: 'm-4',
})

Generated CSS output:

css
/* pika({ __shortcut: 'flex-center', gap: '1rem' }) */
.a { display: flex; }
.b { align-items: center; }
.c { justify-content: center; }
.d { gap: 1rem; }

/* pika({ __shortcut: 'm-4' }) */
.e { margin: 1rem; }

Order of Properties

When using __shortcut, the shortcut styles are inserted before the remaining properties in the definition. This means properties defined alongside __shortcut can override shortcut values.

The defineShortcut() Helper

Use defineShortcut() as a type-safe identity helper for individual shortcut definitions. It provides full TypeScript autocomplete:

ts
import { defineEngineConfig, defineShortcut } from '@pikacss/unplugin-pikacss'

// defineShortcut() is a type-safe identity helper
// It provides full TypeScript autocomplete for shortcut definitions
const flexCenter = defineShortcut(['flex-center', {
	display: 'flex',
	alignItems: 'center',
	justifyContent: 'center',
}])

const dynamicMargin = defineShortcut({
	shortcut: /^m-(\d+)$/,
	value: m => ({ margin: `${Number(m[1]) * 0.25}rem` }),
	autocomplete: ['m-1', 'm-2', 'm-4'],
})

export default defineEngineConfig({
	shortcuts: {
		shortcuts: [flexCenter, dynamicMargin],
	},
})

Recursive Resolution

Shortcuts can reference other shortcuts by name. Resolution is recursive — a shortcut value can be a string pointing to another registered shortcut:

ts
// Shortcuts can reference other shortcuts — resolution is recursive
const shortcuts = [
	['flex-center', {
		display: 'flex',
		alignItems: 'center',
		justifyContent: 'center',
	}],

	// 'btn' resolves to 'flex-center' (another shortcut) + inline styles
	['btn', [
		'flex-center', // references the shortcut above
		{ padding: '0.5rem 1rem', borderRadius: '0.25rem' },
	]],
]

When pika('btn') is called, the engine resolves 'flex-center' first, then merges the result with the remaining inline styles.

Autocomplete

The plugin registers:

  • __shortcut as an extra property on style definitions, accepting string | string[] values.
  • All static shortcut names as autocomplete suggestions.
  • Dynamic resolutions are automatically fed back into autocomplete via onResolved.

Engine API

Plugins can manage shortcuts programmatically:

  • engine.shortcuts.resolver — the ShortcutResolver instance
  • engine.shortcuts.add(...list) — add shortcut definitions at runtime

Behavior Notes

  • Dynamic resolutions are cached after first resolution.
  • Both static and dynamic rules are stored in the ShortcutResolver which extends AbstractResolver.
  • Invalid shortcut config shapes are silently skipped.
  • Shortcuts can reference other shortcuts — resolution is recursive.
  • Resolution errors are caught and logged as warnings; the original string is returned.

Source Reference

  • packages/core/src/internal/plugins/shortcuts.ts

Next