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
- Shortcut definitions are collected from
config.shortcuts.shortcutsduringrawConfigConfigured. - 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.
- The plugin operates on two hooks:
transformStyleItems— string style items are checked against theShortcutResolver. If matched, the resolved items replace the original string.transformStyleDefinitions— when a style definition contains a__shortcutproperty, the shortcut is resolved and the resulting style definitions are inserted before the remaining properties of the current definition.
- Unmatched shortcut strings are returned unchanged (passed through as-is).
Config
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.
// String form: autocomplete-only, no resolution rule
const shortcut = 'flex-center'Tuple Form — Static
type TupleFormStatic = [shortcut: string, value: Arrayable<ResolvedStyleItem>]The value can be a StyleDefinition object, a string referencing another shortcut, or an array of both:
// 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
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:
// 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:
// 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
// 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:
// 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:
/* 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:
// 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:
/* 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:
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:
// 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:
__shortcutas an extra property on style definitions, acceptingstring | 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— theShortcutResolverinstanceengine.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
ShortcutResolverwhich extendsAbstractResolver. - 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
- Continue to Plugin System Overview