Skip to main content

Defining config

defineConfig creates a custom set of cva, cx, and compose functions that share the same configuration. This lets you apply global transformations — such as merging conflicting Tailwind classes or adding a class prefix — without modifying every component individually.

The DefineConfigOptions interface

defineConfig accepts an optional options object with a hooks property:

hooks.onComplete

Called with the final concatenated class string after all variants, compound variants, and extra class/className props have been resolved. Whatever string you return replaces the output.

hooks["cx:done"]

cx:done is deprecated. Use onComplete instead. Both hooks perform the same function, but cx:done may be removed in a future release.

Use case: integrating tailwind-merge globally

The most common use of defineConfig is wiring in tailwind-merge so that class conflicts are resolved everywhere, automatically:
lib/utils.ts
Because onComplete receives the fully-assembled class string, twMerge runs once per call regardless of how many variants or compound variants contributed to the output.

Use case: adding a class name prefix

If your design system requires a vendor prefix on all generated classes, you can apply it in onComplete:
lib/utils.ts
This example is illustrative. Real-world prefix requirements vary; adjust the transformation to match your system’s class naming scheme.

Re-exporting the configured instance

The recommended pattern is to create the configured instance once and re-export it so all components in your application use the same cva, cx, and compose:
1

Create a utils module

lib/utils.ts
2

Import from your utils module in components

components/button.ts
Components that import from lib/utils automatically benefit from the configured hooks. You do not need to change any component-level code when the global configuration changes.