lism.config.js
By placing a lism.config.js (or lism.config.mjs) file in the root of your project, you can customize component behavior (rather than styles).
Registering the Vite / Astro plugin (required)
To make lism.config.js take effect, you must register the plugin in your Vite (or Astro) config file. Without registration, the file is ignored and default settings are used.
Use the integrated plugin provided by @lism-css/plugin. A single registration enables config loading (so the JS runtime reads lism.config.js), dynamic CSS build (changes are automatically reflected in dev/build CSS), and automatic type generation (lism-env.d.ts) all at once.
pnpm add -D @lism-css/pluginimport { defineConfig } from 'astro/config';import { lismCss } from '@lism-css/plugin/astro';
export default defineConfig({ integrations: [lismCss()],});For Next.js, use withLism() from @lism-css/plugin/next instead of the Vite / Astro plugin. See Setting up with Next.js for the setup steps.
The plugin auto-detects lism.config.js then lism.config.mjs from the project root. To use a file at a different location, specify the path via the configPath option:
integrations: [lismCss({ configPath: './config/lism.config.js' })],Format
export default { props: { hoge: { ... }, foo: { ... }, ... }, tokens: { hoge: { ... }, foo: { ... }, ... }, traits: { isHoge: 'is--hoge', setFoo: 'set--foo', ... },};/**
* isVar: 1 → クラス出力はせずstyle属性での変数出力のみ (--bdw, --keycolor など)
* bp: 0(= bp 省略時のデフォルト)→ Prop-valユーティリティクラス化されなければ、style属性で出力するだけ。
* bp: 1 → .-prop と --prop の セットがベースにあり、.-prop_bp と .--prop_bp で ブレイクポイント指定できる。
* .-prop{property:var(--prop)} が基本で、ユーティリティクラスは .-prop:val{property:value} となる。
*
* ↓コンポーネント処理で使用される
* tokenClass: 1 → 対応するトークン値がそのまま全てユーティリティクラス化されるもの。
* shorthands: → コンポーネント側で短く書くための設定
*
* ↓SCSS出力で使用される
* alwaysVar: 1 → state変数扱い。 .-prop,[class*=-prop:] {property:var(--prop)} の base 出力となり、
* ユーティリティクラスは --prop をセットする形になる。
* 加えて BPクラスも .-prop_$bp { property: var(--prop); --prop: var(--prop_$bp) !important; } を出力し、
* 常に --prop が当該要素の現在値になるよう上書きされる(consumer が --prop を参照できる)。
* important: 1 → !important を付けて最終的に出力する
*/
const PLACE_PRESETS = ['start', 'center', 'end'] as const;
const PLACE_FX_PRESETS = ['flex-start', 'flex-end'] as const;
const PLACE_SHORTHANDS = { s: 'start', e: 'end', c: 'center', fs: 'flex-start', fe: 'flex-end' } as const;
export default {
f: { prop: 'font', presets: ['inherit'] },
fz: { prop: 'fontSize', token: 'fz', tokenClass: 1, bp: 1 },
fw: {
prop: 'fontWeight',
token: 'fw',
tokenClass: 1,
presets: ['100', '200', '300', '400', '500', '600', '700', '800', '900'],
},
ff: { prop: 'fontFamily', token: 'ff', tokenClass: 1 },
fs: { prop: 'fontStyle', presets: ['italic'], shorthands: { i: 'italic' } },
lh: {
prop: '--hl',
isVar: 1,
token: 'hl',
tokenClass: 1,
utils: { '1': '0px' },
},
hl: {
prop: '--hl',
isVar: 1,
token: 'hl',
tokenClass: 1,
bp: 1,
// hl="0" で half-leading なし (--hl:0px) を表現できるようにする互換ユーティリティ。
// lh="1"(互換ショートカット)の .-lh:1 と同じ出力にし、正規 prop の hl 側でも揃えられるようにする。
utils: { '0': '0px' },
},
lts: { prop: 'letterSpacing', token: 'lts', tokenClass: 1 },
ta: { prop: 'textAlign', presets: ['center', 'left', 'right'] },
td: { prop: 'textDecoration', utils: { none: 'none' } },
tt: { prop: 'textTransform', utils: { upper: 'uppercase', lower: 'lowercase' } },
// te: { prop: 'textEmphasis', presets: ['filled'] },
// tsh: { prop: 'textShadow' },
d: {
prop: 'display',
presets: ['none', 'block', 'flex', 'inline-flex', 'grid', 'inline-grid', 'inline', 'inline-block'],
bp: 1,
},
o: { prop: 'opacity', presets: ['0'], token: 'o', tokenClass: 1 },
v: { prop: 'visibility', presets: ['hidden'] },
ov: { prop: 'overflow', presets: ['hidden', 'auto', 'clip'] },
'ov-x': { prop: 'overflowX', presets: ['clip', 'auto', 'scroll'] },
'ov-y': { prop: 'overflowY', presets: ['clip', 'auto', 'scroll'] },
// overflow-clip-margin → safariで使えない
ar: {
prop: 'aspectRatio',
presets: ['21/9', '16/9', '3/2', '1/1'], // 4/3, 2/1
token: 'ar',
tokenClass: 1,
bp: 1,
},
// size
w: { prop: 'width', utils: { fit: 'fit-content' }, presets: ['100%'], token: 'sz', bp: 1 },
h: { prop: 'height', utils: { fit: 'fit-content' }, presets: ['100%'], token: 'sz', bp: 1 },
'min-w': { prop: 'minWidth', presets: ['100%'], token: 'sz', bp: 1 },
'max-w': { prop: 'maxWidth', presets: ['100%'], token: 'sz', bp: 1 },
'min-h': { prop: 'minHeight', presets: ['100%'], token: 'sz', bp: 1 },
'max-h': { prop: 'maxHeight', presets: ['100%'], token: 'sz', bp: 1 },
contentSize: { isVar: 1, presets: ['s', 'm', 'l', 'xl'], token: 'sz' },
sz: { prop: 'inlineSize', token: 'sz' },
'min-sz': { prop: 'minInlineSize', token: 'sz' },
'max-sz': {
prop: 'maxInlineSize',
token: 'sz',
tokenClass: 1,
presets: ['full', 'bleed'],
exUtility: {
full: '',
bleed: '',
},
},
bsz: { prop: 'blockSize', token: 'sz' },
'min-bsz': { prop: 'minBlockSize', token: 'sz' },
'max-bsz': { prop: 'maxBlockSize', token: 'sz' },
// bg
bg: { prop: 'background' },
bgi: { prop: 'backgroundImage' },
bgr: { prop: 'backgroundRepeat', presets: ['no-repeat'] },
bgp: { prop: 'backgroundPosition', presets: ['center'] },
bgsz: { prop: 'backgroundSize', presets: ['cover', 'contain'] },
// bga: { prop: 'backgroundAttachment' }, // fixed
// bgo: { prop: 'backgroundOrigin' }, // border, padding, content
// bgblend: { prop: 'backgroundBlendMode' },
// bgclip: {
// prop: 'backgroundClip',
// presets: ['text'],
// },
bgc: {
prop: 'backgroundColor',
presets: ['base', 'base-2', 'text', 'brand', 'accent', 'inherit', 'transparent'],
token: 'color',
exUtility: { inherit: { 'background-color': 'inherit' } },
alwaysVar: 1,
},
c: {
// Note: bg系(bgclip)より後にくるように。
prop: 'color',
presets: ['base', 'text', 'text-2', 'brand', 'accent', 'inherit'],
token: 'color',
exUtility: {
inherit: { color: 'inherit' }, // --c ではなく color で出力したい
// mix: {'--_c1:currentColor;--_c2:transparent;--c:color-mix(in srgb, var(--_c1) var(--_mix-c, 50%), var(--_c2))'},
},
alwaysVar: 1,
},
keycolor: { isVar: 1, token: 'color' },
bd: { prop: 'border', presets: ['none'] },
bds: { isVar: 1, presets: ['dashed', 'dotted', 'double'] },
bdc: {
isVar: 1,
presets: ['brand', 'accent', 'divider', 'inherit', 'transparent'],
utils: { current: 'currentColor' },
token: 'color',
},
bdw: { isVar: 1, bp: 1 }, // --bdw のみ
'bd-x': { prop: 'borderInline' },
'bd-y': { prop: 'borderBlock' },
'bd-s': { prop: 'borderInlineStart' },
'bd-e': { prop: 'borderInlineEnd' },
'bd-bs': { prop: 'borderBlockStart' },
'bd-be': { prop: 'borderBlockEnd' },
'bd-t': { prop: 'borderTop' },
'bd-b': { prop: 'borderBottom' },
'bd-l': { prop: 'borderLeft' },
'bd-r': { prop: 'borderRight' },
bdrs: {
prop: 'borderRadius',
presets: ['0'],
token: 'bdrs',
tokenClass: 1,
bp: 1,
alwaysVar: 1,
},
'bdrs-tl': { prop: 'borderTopLeftRadius', token: 'bdrs' },
'bdrs-tr': { prop: 'borderTopRightRadius', token: 'bdrs' },
'bdrs-br': { prop: 'borderBottomRightRadius', token: 'bdrs' },
'bdrs-bl': { prop: 'borderBottomLeftRadius', token: 'bdrs' },
'bdrs-ss': { prop: 'borderStartStartRadius', token: 'bdrs' },
'bdrs-se': { prop: 'borderStartEndRadius', token: 'bdrs' },
'bdrs-es': { prop: 'borderEndStartRadius', token: 'bdrs' },
'bdrs-ee': { prop: 'borderEndEndRadius', token: 'bdrs' },
bxsh: { prop: 'boxShadow', utils: { 0: 'none' }, token: 'bxsh', tokenClass: 1, bp: 1 },
// position
pos: {
prop: 'position',
presets: ['static', 'fixed', 'sticky', 'relative', 'absolute'],
bp: 1,
},
z: { prop: 'zIndex', presets: ['-1', '0', '1', '99'] },
t: { prop: 'top', utils: { 0: '0%' }, presets: ['50%', '100%'], token: 'space' },
l: { prop: 'left', utils: { 0: '0%' }, presets: ['50%', '100%'], token: 'space' },
r: { prop: 'right', utils: { 0: '0%' }, presets: ['50%', '100%'], token: 'space' },
b: { prop: 'bottom', utils: { 0: '0%' }, presets: ['50%', '100%'], token: 'space' },
i: { prop: 'inset', utils: { 0: '0%' }, token: 'space' },
'i-x': { prop: 'insetInline', token: 'space' },
'i-y': { prop: 'insetBlock', token: 'space' },
'i-s': { prop: 'insetInlineStart', token: 'space' },
'i-e': { prop: 'insetInlineEnd', token: 'space' },
'i-bs': { prop: 'insetBlockStart', token: 'space' },
'i-be': { prop: 'insetBlockEnd', token: 'space' },
// space
p: {
prop: 'padding',
presets: ['0'],
token: 'space',
tokenClass: 1,
alwaysVar: 1,
bp: 1,
},
px: { prop: 'paddingInline', presets: ['0'], token: 'space', tokenClass: 1, bp: 1 },
py: { prop: 'paddingBlock', presets: ['0'], token: 'space', tokenClass: 1, bp: 1 },
ps: { prop: 'paddingInlineStart', token: 'space', bp: 1 },
pe: { prop: 'paddingInlineEnd', token: 'space', bp: 1 },
pbs: { prop: 'paddingBlockStart', token: 'space', bp: 1 },
pbe: { prop: 'paddingBlockEnd', token: 'space', bp: 1 },
pl: { prop: 'paddingLeft', token: 'space' },
pr: { prop: 'paddingRight', token: 'space' },
pt: { prop: 'paddingTop', token: 'space' },
pb: { prop: 'paddingBottom', token: 'space' },
m: {
prop: 'margin',
presets: ['auto', '0'],
token: 'space',
tokenClass: 1,
alwaysVar: 1,
bp: 1,
},
mx: { prop: 'marginInline', presets: ['auto', '0'], token: 'space', tokenClass: 1, bp: 1 },
my: { prop: 'marginBlock', presets: ['auto', '0'], token: 'space', tokenClass: 1, bp: 1 },
ms: { prop: 'marginInlineStart', presets: ['auto'], token: 'space', bp: 1 },
me: { prop: 'marginInlineEnd', presets: ['auto'], token: 'space', bp: 1 },
mbs: { prop: 'marginBlockStart', token: 'space', bp: 1, presets: ['auto', '0'], tokenClass: 1 },
mbe: { prop: 'marginBlockEnd', presets: ['auto'], token: 'space', bp: 1 },
ml: { prop: 'marginLeft', token: 'space' },
mr: { prop: 'marginRight', token: 'space' },
mt: { prop: 'marginTop', token: 'space' },
mb: { prop: 'marginBottom', token: 'space' },
g: {
prop: 'gap',
presets: ['0', 'inherit'],
exUtility: { inherit: { gap: 'inherit' } },
token: 'space',
tokenClass: 1,
bp: 1,
},
cg: { prop: 'columnGap', token: 'space' },
rg: { prop: 'rowGap', token: 'space' },
cols: { isVar: 1, bp: 1 },
rows: { isVar: 1, bp: 1 },
// flex
fxf: { prop: 'flexFlow' },
fxw: { prop: 'flexWrap', presets: ['wrap'], bp: 1 },
fxd: { prop: 'flexDirection', presets: ['column', 'column-reverse', 'row-reverse'], bp: 1 },
fx: { prop: 'flex', presets: ['1'], bp: 1 },
fxg: { prop: 'flexGrow', presets: ['1'] },
fxsh: { prop: 'flexShrink', presets: ['0'] },
fxb: { prop: 'flexBasis', bp: 1 },
// grid
// gd: { prop: 'grid' },
gt: {
prop: 'gridTemplate',
bp: 1,
},
gta: { prop: 'gridTemplateAreas', bp: 1 },
gtc: {
prop: 'gridTemplateColumns',
presets: ['subgrid'],
bp: 1,
},
gtr: {
prop: 'gridTemplateRows',
presets: ['subgrid'],
bp: 1,
},
gaf: { prop: 'gridAutoFlow', presets: ['row', 'column'], bp: 1 }, //dense
gac: { prop: 'gridAutoColumns' },
gar: { prop: 'gridAutoRows' },
// grid item
ga: { prop: 'gridArea', utils: { '1/1': '1 / 1' }, bp: 1 },
gc: { prop: 'gridColumn', utils: { '1/-1': '1 / -1' }, bp: 1 },
gr: { prop: 'gridRow', utils: { '1/-1': '1 / -1' }, bp: 1 },
gcs: { prop: 'gridColumnStart' },
gce: { prop: 'gridColumnEnd' },
grs: { prop: 'gridRowStart' },
gre: { prop: 'gridRowEnd' },
// places
// -(ai|ac|ji|jc|aslf|jslf): / -$1:
ai: {
prop: 'alignItems',
presets: [...PLACE_PRESETS, 'stretch', ...PLACE_FX_PRESETS],
shorthands: PLACE_SHORTHANDS,
bp: 1,
},
ac: {
prop: 'alignContent',
presets: [...PLACE_PRESETS, ...PLACE_FX_PRESETS],
utils: { between: 'space-between' },
shorthands: PLACE_SHORTHANDS,
bp: 1,
},
ji: {
prop: 'justifyItems',
presets: [...PLACE_PRESETS, 'stretch', ...PLACE_FX_PRESETS],
shorthands: PLACE_SHORTHANDS,
bp: 1,
},
jc: {
prop: 'justifyContent',
presets: [...PLACE_PRESETS, ...PLACE_FX_PRESETS],
utils: { between: 'space-between' },
shorthands: PLACE_SHORTHANDS,
bp: 1,
},
pi: { prop: 'placeItems', presets: PLACE_PRESETS },
pc: { prop: 'placeContent', presets: PLACE_PRESETS },
aslf: {
prop: 'alignSelf',
presets: [...PLACE_PRESETS, 'stretch'],
shorthands: PLACE_SHORTHANDS,
},
jslf: {
prop: 'justifySelf',
presets: [...PLACE_PRESETS, 'stretch'],
shorthands: PLACE_SHORTHANDS,
},
pslf: { prop: 'placeSelf', presets: PLACE_PRESETS },
order: { prop: 'order', presets: ['0', '-1', '1'], bp: 1 },
// transform
// translate: {
// prop: 'translate',
// utils: {
// '-50X': '-50% 0',
// '-50Y': '0 -50%',
// '-50XY': '-50% -50%',
// },
// },
// rotate: {
// prop: 'rotate',
// utils: {
// [`45`]: '45deg',
// '-45': '-45deg',
// [`90`]: '90deg',
// '-90': '-90deg',
// // '180': '180deg',
// },
// },
// scale: {
// prop: 'scale',
// utils: {
// '-X': '-1 1',
// '-Y': '1 -1',
// '-XY': '-1 -1',
// },
// },
// others
ovw: { prop: 'overflowWrap', presets: ['anywhere'] },
whs: { prop: 'whiteSpace', presets: ['nowrap'] },
// wordbreak: { prop: 'wordBreak', utils: { keep: 'keep-all', all: 'break-all' } },
float: { prop: 'float', presets: ['left', 'right'] },
clear: { prop: 'clear', presets: ['both'] },
iso: { prop: 'isolation', presets: ['isolate'] },
wm: { prop: 'writingMode', presets: ['vertical-rl'], bp: 1 },
} as const; Customization example
Here’s an example configuration:
import DEFAULT_CONFIG from 'lism-css/default-config';const { props } = DEFAULT_CONFIG;
export default { props: { // Add presets to an existing prop ta: { presets: [...(props.ta.presets || []), 'justify'] }, // Add a utility value to an existing prop p: { utils: { box: '2em' } }, // Add a brand-new prop (filter is not in defaults) filter: { utils: { blur: 'blur(3px)' } }, }, tokens: { // Define tokens as a { key: value } map (deep-merged into the defaults) // → emits :root { --lts--2xl: .5em } and auto-generates the -lts:2xl utility lts: { '2xl': '.5em' }, }, traits: { // Add props for Trait (is--* / has--*) output isHoge: 'is--hoge', },};With the above customization, the following behavior is added to Lism components:
ta='justify'→ outputs-ta:justifyp='box'→ outputs-p:boxfilter='blur'→ outputs-filter:blurlts='2xl'→ outputs-lts:2xlisHoge→ outputsis--hoge
<Box p="box" ta="justify" filter="blur" lts="2xl" isHoge>Box</Box>
↓ Output
<div class="l--box is--hoge -p:box -ta:justify -filter:blur -lts:2xl">Box</div>Added props / traits are also unlocked for types
When you use the integrated plugin (with type generation enabled), props / traits added in lism.config.js are also automatically unlocked on the type side via lism-env.d.ts (emitted as CustomPropRegistry / CustomTraitRegistry augmentations). So new props / traits like <Box filter="blur" ... isHoge> above do not raise type errors in your editor or astro check. No hand-written type extension is needed (commit lism-env.d.ts to git).
Note that adding values to existing props (such as ta="justify") never causes a type error to begin with, since those accept arbitrary strings (they just won’t appear in completion candidates).
Note that adding props in lism.config.js only changes the HTML output from components — the styles for the added utility classes are not generated on their own. See How to load additional styles for ways to apply them (automatic via the plugin / CLI / SCSS).
Enabling xs / xl breakpoints
The default breakpoints are xs: 0 (disabled) / sm: 480px / md: 800px / lg: 1120px / xl: 0 (disabled). A value of 0 means “disabled — no CSS query is output”.
The easiest way to enable xs or xl is to specify the sizes in the breakpoints key of lism.config.js:
export default { breakpoints: { xs: '360px', // Enable xs xl: '1400px', // Enable xl },};This is all it takes. Every Property Class that supports responsive output (bp: 1) will then also emit responsive classes for xs / xl (e.g., -p_xs / -p_xl) — no per-prop configuration is needed. When you are using the @lism-css/plugin integrated plugin, these changes are automatically reflected in the dev server and production build CSS.
This also lets you use xs / xl in object notation on the component side:
<Box p={{ base: 20, xs: 10, sm: 30 }} />To have xs / xl appear in type completion as well, see the Responsive page. If you are using the integrated plugin (@lism-css/plugin), lism-env.d.ts is generated automatically and no hand-written type extension is needed.
Even when you load full.css, xs / xl are disabled by default (only sm / md / lg are emitted). To use them, enable them by specifying sizes in breakpoints, just as above.
Enabling xs / xl adds a block for each active breakpoint to every Property Class that uses bp: 1, which increases the CSS size. This feature is designed to be used together with CSS purge. If you are not using purge, consider using the list form of bp (e.g., bp: ('sm', 'md')) to restrict which breakpoints are output on a per-prop basis.
For projects using SCSS directly, you can also enable xs / xl via the $breakpoints SCSS variable override (see SCSS Customization).
How to load additional styles
Adding props in lism.config.js alone does not produce styles for the corresponding utility classes. Use one of the following approaches to add the styles.
Automatic reflection when using the Vite / Astro plugin
If you have registered the @lism-css/plugin integrated plugin (lismCss() from @lism-css/plugin/vite or @lism-css/plugin/astro), any additions or changes to props / tokens in lism.config.js are automatically reflected in the CSS, both in the dev server and in production builds. No manual CLI build is needed.
When the dev server is running, editing lism.config.js triggers HMR to regenerate the CSS.
Hand-write styles for small additions
For small additions, you don’t need to rebuild via the CLI or reconfigure SCSS. The Lism Props :value notation combined with hand-written rules in global.css is enough.
@layer lism-base { :root { --lts--2xl: 0.15em; }}
/* Property Classes are not wrapped in @layer */.-lts\:2xl { letter-spacing: var(--lts--2xl);}<Text lts=":2xl">...</Text>Switch to the CLI / SCSS routes below only when you want to extend tokens systematically.
Build CSS using the lism-css CLI command
For projects that do not use Vite or Astro (plain SCSS setups, other bundlers, etc.), run the lism-css build command provided by @lism-css/plugin to reflect lism.config.js into the CSS. This is not a legacy-only path — it is the primary route for that type of setup.
npx lism-css buildIn this example, the following styles would be automatically generated into lism-css/main.css by this command:
.-ta\:justify { text-align: justify;}.-p\:box { padding: 2em;}.-filter\:blur { filter: blur(3px);}.-lts\:2xl { letter-spacing: var(--lts--2xl);}When you give a value in tokens, the build generates both the utility class that references the token (such as .-lts\:2xl { letter-spacing: var(--lts--2xl) }) and the referenced CSS variable itself (the actual token value, such as :root { --lts--2xl: .5em }). Note that a key whose value is '-' only registers the name and does not output a value: no :root declaration is emitted, and the real value is defined in hand-written SCSS (mainly used for color / palette).
On the other hand, is-- class styles are not auto-generated, so you need to define and load them manually.
@layer lism-trait { .is--hoge { /* ... */ }}Since this command rebuilds the package styles, it must be run each time the package is updated.
Note that full.css / full_no_layer.css are not rebuilt by default. If you use full.css, run the build with the --full option.
npx lism-css build --fullOverriding SCSS files
You can also override SCSS variables in line with your lism.config.js configuration before loading the styles. See SCSS Customization for details on SCSS variables.
// Configuration overrides@use '../path-to/node_modules/lism-css/scss/setting' with ( $props: ( 'ta': ( utilities: ( 'justify': 'justify', ), ), 'p': ( utilities: ( 'box': '2em', ), ), 'filter': ( utilities: ( 'blur': 'blur(3px)', ), ), 'lts': ( utilities: ( '2xl': 'var(--lts--2xl)', ), ), ));
// Load the Lism SCSS file@use '../path-to/node_modules/lism-css/scss/main';
// Append token definitions@layer lism-base { :root { --lts--2xl: 0.15em; }}