Custom Shorthands

Custom shorthands define build-time prop aliases that apply one value to multiple CSS properties. They are plugin options, not design tokens, so define them in your bundler configuration rather than devup.json.

1DevupUI({
2  shorthands: {
3    insetX: ['left', 'right'],
4    scrollMarginX: ['scrollMarginLeft', 'scrollMarginRight'],
5  },
6})
1DevupUI({
2  shorthands: {
3    insetX: ['left', 'right'],
4    scrollMarginX: ['scrollMarginLeft', 'scrollMarginRight'],
5  },
6})
1const pinned = <Box insetX={0} />
2const responsive = <Box insetX={[0, null, 'auto']} />
3const interactive = <Box _hover={{ insetX: 4 }} />
4const nested = <Box selectors={{ '& > *': { insetX: 2 } }} />
1const pinned = <Box insetX={0} />
2const responsive = <Box insetX={[0, null, 'auto']} />
3const interactive = <Box _hover={{ insetX: 4 }} />
4const nested = <Box selectors={{ '& > *': { insetX: 2 } }} />

For insetX={4}, both left and right receive the same resolved value. Every target follows the existing Devup UI value rules.

Plugin Configuration

Vite

1import { DevupUI } from '@devup-ui/vite-plugin'
2import { defineConfig } from 'vite'
3
4export default defineConfig({
5  plugins: [
6    DevupUI({
7      shorthands: {
8        insetX: ['left', 'right'],
9      },
10    }),
11  ],
12})
1import { DevupUI } from '@devup-ui/vite-plugin'
2import { defineConfig } from 'vite'
3
4export default defineConfig({
5  plugins: [
6    DevupUI({
7      shorthands: {
8        insetX: ['left', 'right'],
9      },
10    }),
11  ],
12})

Next.js

1import { DevupUI } from '@devup-ui/next-plugin'
2
3const nextConfig = {}
4
5export default DevupUI(nextConfig, {
6  shorthands: {
7    insetX: ['left', 'right'],
8  },
9})
1import { DevupUI } from '@devup-ui/next-plugin'
2
3const nextConfig = {}
4
5export default DevupUI(nextConfig, {
6  shorthands: {
7    insetX: ['left', 'right'],
8  },
9})

The second argument is shared by the Webpack and Turbopack paths.

Webpack

1import { DevupUIWebpackPlugin } from '@devup-ui/webpack-plugin'
2
3export default {
4  plugins: [
5    new DevupUIWebpackPlugin({
6      shorthands: {
7        insetX: ['left', 'right'],
8      },
9    }),
10  ],
11}
1import { DevupUIWebpackPlugin } from '@devup-ui/webpack-plugin'
2
3export default {
4  plugins: [
5    new DevupUIWebpackPlugin({
6      shorthands: {
7        insetX: ['left', 'right'],
8      },
9    }),
10  ],
11}

Rsbuild

1import { DevupUI } from '@devup-ui/rsbuild-plugin'
2import { defineConfig } from '@rsbuild/core'
3
4export default defineConfig({
5  plugins: [
6    DevupUI({
7      shorthands: {
8        insetX: ['left', 'right'],
9      },
10    }),
11  ],
12})
1import { DevupUI } from '@devup-ui/rsbuild-plugin'
2import { defineConfig } from '@rsbuild/core'
3
4export default defineConfig({
5  plugins: [
6    DevupUI({
7      shorthands: {
8        insetX: ['left', 'right'],
9      },
10    }),
11  ],
12})

Bun

Use a local preload module when options are required:

1# bunfig.toml
2[test]
3preload = ["./devup-ui.preload.ts"]
1# bunfig.toml
2[test]
3preload = ["./devup-ui.preload.ts"]
1// devup-ui.preload.ts
2import { register } from '@devup-ui/bun-plugin/register'
3
4await register({
5  shorthands: {
6    insetX: ['left', 'right'],
7  },
8})
1// devup-ui.preload.ts
2import { register } from '@devup-ui/bun-plugin/register'
3
4await register({
5  shorthands: {
6    insetX: ['left', 'right'],
7  },
8})

Property Names

Target properties may use either camelCase or CSS kebab-case:

1DevupUI({
2  shorthands: {
3    scrollMarginX: ['scrollMarginLeft', 'scroll-margin-right'],
4  },
5})
1DevupUI({
2  shorthands: {
3    scrollMarginX: ['scrollMarginLeft', 'scroll-margin-right'],
4  },
5})

Targets can also use built-in Devup UI shorthands. For example, py expands to both padding-top and padding-bottom:

1DevupUI({
2  shorthands: {
3    sectionSpacing: ['py', 'gap'],
4  },
5})
1DevupUI({
2  shorthands: {
3    sectionSpacing: ['py', 'gap'],
4  },
5})

Type Completion

When the plugin starts, it writes the configured prop names to <distDir>/theme.d.ts (df/theme.d.ts by default). The declaration augments DevupProps, so completion and type checking work for:

  • Component props such as <Box insetX={0} />
  • Responsive arrays such as insetX={[0, null, 'auto']}
  • Pseudo selectors such as _hover={{ insetX: 4 }}
  • Custom selectors such as selectors={{ '& > *': { insetX: 2 } }}

If tsconfig.json limits include to your source directory, include the generated declaration as well:

1{
2  "include": ["src", "df/*.d.ts"]
3}
1{
2  "include": ["src", "df/*.d.ts"]
3}

Restart the build tool after changing shorthands, because bundler configuration changes do not use the devup.json hot-reload path.

Design Tokens vs. Shorthands

Use devup.json for values that belong to the design system, such as colors, typography, lengths, and shadows. Use plugin shorthands for prop vocabulary and extraction behavior.

1// $contentX is a design-token value; insetX is a custom prop alias.
2const content = <Box insetX="$contentX" />
1// $contentX is a design-token value; insetX is a custom prop alias.
2const content = <Box insetX="$contentX" />