nextui-org / tailwind-variants Goto Github PK
View Code? Open in Web Editor NEW๐ฆ Tailwindcss first-class variant API
Home Page: https://tailwind-variants.org
License: MIT License
๐ฆ Tailwindcss first-class variant API
Home Page: https://tailwind-variants.org
License: MIT License
Describe the bug
Simply installed the package, and immediatly ts server tells me it cannot find the declaration file or the module. Using it in a NextJs project with the following tsconfig:
EDIT: installed tailwind-variant at version ^0.1.10
NextJS Version is 13.4.9, but since its TS related i don't think thats the problem.
Expected behavior
Typings just working without research.
Desktop (please complete the following information):
Describe the bug
Doesn't work when using Turbopack in Nextjs app dir
To Reproduce
Steps to reproduce the behavior:
npx create-next-app@latest -e with-turbopack
next dev --turbo
/** @type {import('tailwindcss').Config} */
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { withTV } = require('tailwind-variants/transformer');
module.exports = withTV({
darkMode: 'class',
content: [
'./app/**/*.{js,ts,jsx,tsx}', // Note the addition of the `app` directory.
'./pages/**/*.{js,ts,jsx,tsx}'
],
future: {
hoverOnlyWhenSupported: true
},
theme: {
extend: {}
},
plugins: []
});
import { tv } from 'tailwind-variants';
const Button = () => {
const button = tv({
base: 'font-medium bg-blue-500 text-white rounded-full active:opacity-80',
variants: {
color: {
primary: 'bg-blue-500 text-white',
secondary: 'bg-purple-500 text-white'
},
size: {
sm: 'text-sm',
md: 'text-base',
lg: 'px-4 py-3 text-lg'
}
},
compoundVariants: [
{
size: ['sm', 'md'],
class: 'px-3 py-1'
}
],
defaultVariants: {
size: 'md',
color: 'primary'
}
});
return (
<button className={button({ size: 'sm', color: 'secondary' })}>
Click me
</button>
);
};
export default Button;
Expected behavior
It can work
Screenshots
Desktop (please complete the following information):
Smartphone (please complete the following information):
Additional context
Describe the bug
why passing twMergeConfig
to tv function I get this error
Type 'Partial<Config>' is not assignable to type 'Config'.
Types of property 'cacheSize' are incompatible.
Type 'number | undefined' is not assignable to type 'number'.
Type 'undefined' is not assignable to type 'number'.
the Problem is in tv typing where twMergeConfig
is type of TwMergeConfig
import type {Config as TwMergeConfig} from "tailwind-merge";
export type TWMConfig = {
twMergeConfig?: TwMergeConfig;
};
however, inside tailwind-merge
the config type is
import { Config } from './types';
type CreateConfigSubsequent = (config: Config) => Config;
export declare function extendTailwindMerge(configExtension: Partial<Config> | CreateConfigSubsequent, ...createConfig: CreateConfigSubsequent[]): (...classLists: import("./tw-join").ClassNameValue[]) => string;
To Reproduce
check vscode
Expected behavior
twMergeConfig
has to correct typing
Describe the bug
I'm working on a modal component that uses slots
, and that also uses responsive styles to ensure that all of the fullscreen
styles are applied until the sm
breakpoint. One piece of this, is ensuring that the hide modal button is shown when fullscreen === true
or when on mobile, even when hideCloseButton === true
. My understanding is that the below style object should cover this. But sadly I'm having some trouble getting this working properly.
const styles = tv(
{
slots: {
modal: "absolute",
dialog: "max-h-screen overflow-y-auto bg-white",
closeButton: "absolute right-8 top-8 cursor-pointer text-sm text-black"
},
variants: {
fullscreen: {
true: {
modal: "h-full w-full",
dialog: "h-full w-full",
closeButton: "!block"
},
false: {
modal: "h-max w-max",
dialog: "h-max w-max rounded-lg"
}
},
hideCloseButton: {
true: {
closeButton: "hidden"
}
}
}
},
{ responsiveVariants: ["sm"] }
);
To Reproduce
Link to minimal repro here: https://codesandbox.io/s/confident-http-rvdg8c?file=/src/index.tsx
Expected behavior
The close modal button should display in the following scenarios:
{ hideCloseButton: true, fullscreen: true }
{ hideCloseButton: true, size: 'initial' }
{ hideCloseButton: false | undefined, ...anyOtherProps }
The close modal button should NOT display in the following scenarios:
{ hideCloseButton: true, size: 'md' }
{ hideCloseButton: true, fullscreen: false | undefined }
Desktop (please complete the following information):
Describe the bug
Theres a typo at the bottom of the Comparison page.
To Reproduce
Steps to reproduce the behavior:
Expected behavior
Originally posted by lewebsimple March 10, 2023
As the title says, is it possible to add extra slots when extending a component ?
Consider the following:
import { tv } from "tailwind-variants";
const section = tv({
slots: {
wrapper: '',
inner: '',
},
});
const extended = tv({
extend: section,
slots: {
inner: 'py-12',
extraSlot: '',
}
});
// This doesn't work as extended().extraSlot is undefined, but commenting out `extend: section` makes it work
console.log(extended().extraSlot())
Of course adding the missing slots in the parent component with empty values would fix the problem, but this means we have to know every possible slot name in advance ... which is not very convenient DX or downright impossible for packaged libraries.
Am I missing something ?
If extendcolor and responsiveVariants are enabled, class merge is not performed.
In the following example, the text is fine, but the border is not merged.
Describe the bug
When using the VariantProps generic all of the returned types are any
instead of being literals.
To Reproduce
tv
function in Typescript that includes variants.const circle = tv({
variants: {
size: {
md: ["w-[580px] h-[580px]"],
lg: ["w-[1280px] h-[1280px]"],
},
contrast: {
low: ["bg-gray-100", "dark:bg-purple-900"],
high: ["bg-gray-200", "dark:bg-purple-800"],
},
},
defaultVariants: {
size: "md",
contrast: "high",
},
})
type CircleType = VariantProps<typeof circle>
Expected behavior
variant props to be literals. ie: size: 'md' | 'lg'
Screenshots
Screenshots are added above in description
Desktop (please complete the following information):
Smartphone (please complete the following information):
Additional context
The actual tv
function isn't strongly typed either. I can add whatever I want to defaultVariants
whether its a variant or not.
I noticed defaultVariants
properties are being intellisensed by the TailwindCSS IntelliSense Extension when using the settings snippet provided in the docs:
{
"tailwindCSS.experimental.classRegex": [
["tv\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"]
]
}
These properties already have the TS types inferred correctly, so I think the RegEx simply needs to be updated to ignore this property.
Describe the bug
Defining a responsive variant for specific variants using the object syntax (described on #24) isn't returning the correct types nor is it returning the expected classes.
To Reproduce
Steps to reproduce the behavior:
components/button.styles.ts
file where the responsive variants are configured for the size
variant onlypages/index.tsx
file to see usage of component and the types of the variants (extracted using VariantProps
on components/button.tsx
file)size
prop and that the classes have not been injected into the <button>
element.Expected behavior
The types should be correctly asserted based on the configuration the developer has instructed for each variant and the classes should be extracted according to the same configuration.
Additional context
It seems that the transformer has this feature working (according to the PR mentioned above), but the tv
API does not seem to have this feature implemented just yet.
Describe the bug
I have extended my tailwind theme with new a new class for a smaller fontSize:
fontSize: {
mini: ['0.65rem', '0.75rem'],
},
But when trying to use it in a tailwind-variants function. It never gets added to the final classes:
e.g.
export const itemDescription = tv({
base: 'm-0 overflow-hidden whitespace-nowrap text-mini text-neutral-400',
})
The only workaround I have found is to override the class like tv({ class: 'text-mini '})
(this makes it work).
Expected behavior
extended tailwind theme options should work in the tv() base classes.
Desktop (please complete the following information):
Hey there ๐,
First, thank you for making this lib possible, it has great features and coming from cva
, it feels nice to use slots and the extend prop.
However, as I was refactoring the project to use tailwind-variants
, I noticed some performance issue...
Here's a repro:
https://github.com/Sliov/cva-tailwind-variants-benchmark
Do you know if that's normal or if there's space for improvement here?
Thank you
Describe the bug
When extending a component with extend
and using it with VariantProps
, it only works when the variants
property is defined in the extending component.
To Reproduce
Take this (solidJS
) code:
const base = tv({
base: "...",
variants: {
hasError: {
true: "border-red-800 outline-red-800",
},
},
});
const extended = tv({
extend: base
});
export interface ExtendedProps extends JSX.SelectHTMLAttributes<HTMLSelectElement>, VariantProps<typeof extended> {}
export const Extended: Component<ExtendedProps> = (props) => {
// Split select element props
const [local, other] = splitProps(props, ["class", "hasError"]);
return (
<select
class={extended({ hasError: local.hasError, class: local.class })}
{...other}
/>
);
};
It throws the following error:
Type 'string | number | boolean | TVScreenPropsValue<{ hasError: { true: string; }; } & TVVariantsDefault<undefined, undefined>, string> | TVScreenPropsValue<...> | undefined' is not assignable to type 'boolean | TVScreenPropsValue<{ hasError: { true: string; }; } & { hasError?: { true?: ClassValue | SlotsClassValue<undefined, undefined>; } | undefined; }, "hasError"> | undefined'.
Type 'string' is not assignable to type 'boolean | TVScreenPropsValue<{ hasError: { true: string; }; } & { hasError?: { true?: ClassValue | SlotsClassValue<undefined, undefined>; } | undefined; }, "hasError"> | undefined'.
Replacing extended
with the following code fixes the issue:
const extended = tv({
extend: base,
variants: {}
});
Expected behavior
I expect it to don't throw on the first variant.
Desktop (please complete the following information):
Smartphone (please complete the following information):
Additional context
no response
Describe the bug
Receive type error when TailwindVariant style contains boolean.
To Reproduce
Steps to reproduce the behavior:
.tsx
fileType boolean is not assignable to string | number | undefined
Expected behavior
There should not be any errors. The boolean should be converted to string under the hood. Or the type should accept boolean.
Screenshots
The setting on tv containing booleans:
The type error received when using the tv style:
Desktop (please complete the following information):
Smartphone (please complete the following information):
Additional context
Please let me know if there is any questions. Thank you.
Describe the bug
When there are variants present, the base classes are not applied.
To Reproduce
Steps to reproduce the behavior:
Expected behavior
Base and variants classes should be applied.
Would like the ability to edit the default config:
type TvConfig = {
twMerge?: boolean,
twMergeConfig?:TwMergeConfig,
responsiveVariants?: string[] | boolean
}
Mostly just want to turn off twMerge
by default
You could do it one of two ways:
import { globalConfig } from 'tailwind-variants'
globalConfig({
twMerge: false
})
...
or
import { createTV } from 'tailwind-variants'
const tv = createTV({
twMerge: false
})
const button = tv({
...
})
...
Describe the bug
When using "extend" prop to compose class names, the prop-types produced in extended TVReturnType aren't correct. Without "boolean" variant, typescript happy, but the type of "props.variant" in the BuyButton component is "string | number | undefined" which looks incorrect too.
To Reproduce
const baseButton = tv({
base: "",
variants: {
variant: {
primary: "",
},
disabled: {
true: "",
},
},
});
const buyButton = tv({
extend: baseButton,
});
const Button = (props: VariantProps<typeof baseButton>) => {
const className = baseButton(props);
return (
<div className="flex gap-3">
<button className={className}>Buy button</button>
</div>
);
};
const BuyButton = (props: VariantProps<typeof buyButton>) => {
const className = buyButton(props);
return (
<div className="flex gap-3">
<button className={className}>Buy button</button>
</div>
);
};
Expected behavior
Props for the "buyButton" inherited properly to let typescript pass without errors and suggest correct variants in autocomplete.
Desktop (please complete the following information):
Additional context
Given the following configuration
const grid = tv({
variants: {
documents: {
true: {},
}
},
defaultVariants: {
documents: true
},
slots: {
general: 'col-span-7 row-span-4 card',
chart: 'card !px-0 col-span-5 relative row-span-4',
documents: 'row-span-6 col-span-5 card',
flow: 'relative row-span-6 card'
},
compoundSlots: [
// {
// slots: ['documents', 'chart', 'general', 'flow'],
// className: 'bg-violet-10',
// documents: false
// },
{
documents: false,
slots: ['documents'],
className: 'hidden'
}, {
documents: false,
slots: ['flow'],
className: 'col-span-12'
}, {
documents: true,
slots: ['flow'],
className: 'col-span-7'
}
]
})
// usage later
const { general, flow, documents, chart } = grid({ documents: true })
// i'd expect to have `col-span-12` applied below
// jsx
<div className={flow()} />
The variants are never applied ๐คทโโ๏ธ (version 0.1.10
).
Maybe I misunderstood how to use them?
Describe the bug
I'm currently evaluating tv
for a project, and have been doing some testing by refactoring an existing typography component. I've noticed that some classes (in this case, leading-x
ones) aren't being added.
To Reproduce
Here is a codesandbox with a minimal repro, showing that the leading classes are not added by tv
, but are added by cva
Expected behavior
All classes listed in the variant's config are added to the output.
Screenshots
If applicable, add screenshots to help explain your problem.
Desktop (please complete the following information):
Describe the bug
A clear and concise description of what the bug is.
To Reproduce
Steps to reproduce the behavior:
Copy paste example code
tv({
base: 'font-bold',
variants: {
size: {
xs: '',
sm: ''
},
flat: {
true: ''
}
},
defaultVariants: {
flat: true,
},
compoundVariants: []
})
Expected behavior
No errors
Desktop (please complete the following information):
Additional context
Add any other context about the problem here.
hello there... while exploring ur website. i saw this code error at this page in last snippet
=> bug
const { base, tab } = tab({ color: "primary" });
=> correct
const { base, tab } = card({ color: "primary" });
Describe the bug
To Reproduce
Steps to reproduce the behavior:
Expected behavior
Screenshots
If applicable, add screenshots to help explain your problem.
Desktop (please complete the following information):
Additional context
Add any other context about the problem here.
Hi,
This is not a bug, may be a feature request.
I find myself keep adding ClassName in each component like this
import { ClassValue } from 'tailwind-variants'
export type HeadingProps = HeadingVariants & {
className?: ClassValue
}
I even played with VariantProps
types locally to un omit the className but the type was messed up, would you consider exporting something like WithClassName
?
type WithClassName<P = unknown> = P & { className?: ClassValue };
Describe the bug
Putting "text-{color}" class in the same variant as "text-{size}" class removes the color class
To Reproduce
Steps to reproduce the behavior:
const config = {
theme: {
colors: {
...
white: '#FFFFFF'
},
fontSize: {
...
'14': '0.875rem'
}
}
}
export const button = tv({
variants: {
intent: {
primary: 'text-white text-14',
},
},
defaultVariants: {
intent: 'primary',
},
})
function Component() {
return <button className={button()}>Button</button>
}
Expected behavior
No tailwind classes should be removed
Screenshots
Notice "text-emerald" has been removed
Desktop (please complete the following information):
Additional context
Add any other context about the problem here.
Describe the bug
Custom shadows get stripped from the classList when used with a color class.
To Reproduce
Steps to reproduce the behavior:
{circle: "0 0px 30px -10px rgba(0, 0, 0, 0.3)"}
shadow-circle shadow-violet-600
hover:shadow-violet-600
, with shadow-circle
strippedshadow-violet-600
, then shadow-circle remains
Expected behavior
Custom shadows should be usable with shadow color utility classes
Great work on this btw!
Is there any way to configure it?
I want margin-top: 65px,
so I wrote mt-[65px] but it's not working.
Code:
<main className="container mx-auto max-w-7xl px-6 flex-grow mt-[65px]">
Extend does not work as expected. I've created a simple example below.
Once "inputBox" is extended, the "slot" is modified and not immutable. It appears that this pull request (PR) is causing this change.
const inputBox = tv({
slots: {
base: "flex",
},
});
console.log("inputBox", inputBox().base()); // flex
const extendedInput = tv({
extend: inputBox,
slots: {
base: "flex1",
},
});
// expected: flex flex1, actual: flex flex1
console.log("extendedInput", extendedInput().base());
// expected: flex, actual: flex flex1
console.log("inputBox", inputBox().base());
I'm curious as to why the implementation of "joinObjects" was changed to a version with side effects.
Describe the bug
In monorepo using Turborepo, when withTV()
was called in a child package to hide settings related to tailwind, writeFileSync()
was called on the client side and compilation failed.
To Reproduce
Steps to reproduce the behavior:
pnpm install
commandpnpm website dev
commandExpected behavior
Can compile even if withTV()
is called in a child package.
Screenshots
Below is a screenshot of the error output to the browser:
and terminal:
pnpm website dev
> [email protected] website /Users/shio/Projects/shio3616/tv-bug
> pnpm --filter @tv-bug/website "dev"
> @tv-bug/[email protected] dev /Users/shio/Projects/shio3616/tv-bug/apps/website
> next dev
- ready started server on 0.0.0.0:3000, url: http://localhost:3000
- event compiled client and server successfully in 318 ms (20 modules)
- wait compiling...
- event compiled client and server successfully in 100 ms (20 modules)
- wait compiling /page (client and server)...
- error ../../node_modules/.pnpm/[email protected][email protected]/node_modules/tailwind-variants/dist/chunk-FUBUDMV2.js:1:0
Module not found: Can't resolve 'fs'
https://nextjs.org/docs/messages/module-not-found
Import trace for requested module:
../../node_modules/.pnpm/[email protected][email protected]/node_modules/tailwind-variants/dist/transformer.js
../../packages/tailwind/src/config.ts
../../packages/tailwind/src/index.ts
./src/component/client-button.tsx
- wait compiling /_error (client and server)...
- error ../../node_modules/.pnpm/[email protected][email protected]/node_modules/tailwind-variants/dist/chunk-FUBUDMV2.js:1:0
Module not found: Can't resolve 'fs'
https://nextjs.org/docs/messages/module-not-found
Import trace for requested module:
../../node_modules/.pnpm/[email protected][email protected]/node_modules/tailwind-variants/dist/transformer.js
../../packages/tailwind/src/config.ts
../../packages/tailwind/src/index.ts
./src/component/client-button.tsx
<w> [webpack.cache.PackFileCacheStrategy] Caching failed for pack: Error: ENOENT: no such file or directory, rename '/Users/shio/Projects/shio3616/tv-bug/apps/website/.next/cache/webpack/client-development-fallback/1.pack.gz_' -> '/Users/shio/Projects/shio3616/tv-bug/apps/website/.next/cache/webpack/client-development-fallback/1.pack.gz
Desktop (please complete the following information):
Additional context
This problem is only specific to monorepo and does not occur with polyrepo.
In fact, a modification like this PR completely eliminates the problem.
Describe the bug
Doesn't look right
To Reproduce
Steps to reproduce the behavior:
Expected behavior
...
Additional context
<svg fill="none" height="1018" viewBox="0 0 1210 1018" width="1210" xmlns="http://www.w3.org/2000/svg" class="absolute -z-10 -translate-y-[40%] animate-[appear_1s_ease]">
is not responsive
Describe the bug
Following the documentation on compound variants generates a TypeScript error when attempting to target multiple variants.
To Reproduce
tailwind-variants
size
key of compoundVariants
cannot target ['sm', 'md']
or else it generatesType 'string' is not assignable to type 'never'.ts(2322)
Expected behavior
I expect no TypeScript errors for basic usage of the compound variants feature.
Desktop (please complete the following information):
"tailwind-variants": "^0.1.5"
Describe the bug
Running command typecheck
failed due to no providing declaration file of utils.js
To Reproduce
typecheck
scriptExpected behavior
Type check must be finished without no errors.
Screenshots
Additional context
You maybe considering allowJS: true
or converting utils.js to TS version.
Before using Tailwind Variants, I created components with Tailwind plugin utility to use on my company's design system.
module.exports = plugin({ addComponents })({
addComponents({
'.btn': {
padding: '...',
margin: '...',
fontSize: '...'
},
'.btn-light': {...},
'.btn-dark': {...},
})
})
And the beauty was that once Tailwind creates the component classes (i.e. .btn
) I could use them with Tailwind variants:
<button class="btn btn-light dark:btn-dark">Button</button>
The idea here is to use the current responsiveVariants
and transform it to accept all sorts of Tailwind variants like dark
and others, not only the responsive ones.
import { tv } from "tailwind-variants";
const button = tv({
base: "font-semibold text-white py-1 px-3 rounded-full active:opacity-80",
variants: {
color: {
primary: "bg-blue-500 hover:bg-blue-700",
secondary: "bg-purple-500 hover:bg-purple-700",
success: "bg-green-500 hover:bg-green-700",
},
size: {
small: "py-0 px-2 text-xs",
medium: "py-1 px-2 text-sm",
large: "py-1.5 px-3 text-md",
},
}
},
{
responsiveVariants: ['sm', 'md'] // `true` to apply to all screen sizes
});
button({
color: {
initial: "primary",
sm: "success",
md: "secondary",
},
size: {
initial: "small",
sm: "medium",
md: "large",
},
});
responsiveVariants
becomes dynamicVariants
import { tv } from "tailwind-variants";
const button = tv({
base: "font-semibold text-white py-1 px-3 rounded-full active:opacity-80",
variants: {
color: {
primary: "bg-blue-500 hover:bg-blue-700",
secondary: "bg-purple-500 hover:bg-purple-700",
success: "bg-green-500 hover:bg-green-700",
},
size: {
small: "py-0 px-2 text-xs",
medium: "py-1 px-2 text-sm",
large: "py-1.5 px-3 text-md",
},
}
},
{
dynamicVariants: ['sm, 'md', 'dark'] // enables the usage of `dark`
});
button({
color: {
initial: "primary",
dark: "success",
},
size: {...},
});
// results in "bg-blue-500 hover:bg-blue-700 dark:bg-green-500 dark:hover:bg-green-700 ..."
// Usage in JSX
const Button = ({ color, size, className, children }) => (
<button className={button({ color, size, className })}>{children}</button>
)
export default () => (
<Button color={{ initial: 'primary', dark: 'success' }} size={{ ... }}>
...
</Button>
)
Describe the bug
Since the use of TWMConfig["twMergeConfig"]
is to be passed to extendTailwindMerge
that takes configs partially, the type of TWMConfig["twMergeConfig"]
should be also partial.
const twMerge = !isEmptyObject(config.twMergeConfig)
? extendTailwindMerge(config.twMergeConfig)
: twMergeBase;
https://github.com/nextui-org/tailwind-variants/blob/main/src/index.js#LL29C24-L29C24
export function extendTailwindMerge(
configExtension: Partial<Config> | CreateConfigSubsequent,
...createConfig: CreateConfigSubsequent[]
) {
return typeof configExtension === 'function'
? createTailwindMerge(getDefaultConfig, configExtension, ...createConfig)
: createTailwindMerge(
() => mergeConfigs(getDefaultConfig(), configExtension),
...createConfig,
)
}
https://github.com/dcastil/tailwind-merge/blob/main/src/lib/extend-tailwind-merge.ts#LL8C1-L18C2
export type TWMConfig = {
/**
* Whether to merge the class names with `tailwind-merge` library.
* It's avoid to have duplicate tailwind classes. (Recommended)
* @see https://github.com/dcastil/tailwind-merge/blob/v1.8.1/README.md
* @default true
*/
twMerge?: boolean;
/**
* The config object for `tailwind-merge` library.
* @see https://github.com/dcastil/tailwind-merge/blob/v1.8.1/docs/configuration.md
*/
twMergeConfig?: TwMergeConfig;
};
https://github.com/nextui-org/tailwind-variants/blob/main/src/config.d.ts#L20
To Reproduce
Steps to reproduce the behavior:
tv
an empty configuration object as shown below:tv(options, {
...config,
twMerge: true,
twMergeConfig: {},
});
Expected behavior
TWMConfig["twMergeConfig"]
should be typed partially.
export type TWMConfig = {
/**
* Whether to merge the class names with `tailwind-merge` library.
* It's avoid to have duplicate tailwind classes. (Recommended)
* @see https://github.com/dcastil/tailwind-merge/blob/v1.8.1/README.md
* @default true
*/
twMerge?: boolean;
/**
* The config object for `tailwind-merge` library.
* @see https://github.com/dcastil/tailwind-merge/blob/v1.8.1/docs/configuration.md
*/
twMergeConfig?: Partial<TwMergeConfig>;
};
Screenshots
If applicable, add screenshots to help explain your problem.
Desktop (please complete the following information):
All desktop environments
Smartphone (please complete the following information):
All smartphone environments
Additional context
None
Describe the bug
text size and text color overwrites each other
const button = tv({
base: 'rounded-sm',
variants: {
variant: {
primary: 'bg-primary text-neutral-white',
secondary: '',
tertiary: ''
},
size: {
small: 'py-2 px-6 text-button-small',
medium: 'py-3.5 px-8 text-button-medium',
normal: 'py-4 px-8 text-button-normal'
}
},
defaultVariants: {
variant: 'primary',
size: 'medium'
}
})
Expected Result
"rounded-sm bg-primary py-3.5 px-8 text-neutral-white text-button-medium"
Result
"rounded-sm bg-primary py-3.5 px-8 text-button-medium"
Describe the bug
The link on the Slots Documentation https://www.tailwind-variants.org/docs/slots#slots-with-responsive-variants
is throwing 404. Please update the link, it is currently referencing to https://www.tailwind-variants.org/docs/responsive-variants
.
To Reproduce
Steps to reproduce the behavior:
Expected behavior
A clear and concise description of what you expected to happen.
Screenshots
If applicable, add screenshots to help explain your problem.
Desktop (please complete the following information):
Smartphone (please complete the following information):
i created a button component using tailwind variants like this:
const button = tv(
{
base: "py-2 px-5 ",
variants: {
variant: {
contained: "rounded-[10px] ",
outlined: "rounded-[10px]",
inlined: "bg-transparent ",
},
},
},
{
responsiveVariants: ["lg"],
}
);
type ButtonVariants = VariantProps;
export type IButtonProps = {
children: React.ReactNode;
} & ButtonVariants;
but when i use this component ,the prettier extenstion formatting on vscode takes to long ... !
and when i remove tailwind variants from this component,prettier formatting working stable and fast !
Expected behavior
dont break another tools and extenstion like prettier !
Describe the bug
First of all, thank you for the library โ enjoying using it so far, it's helped a lot in structuring Tailwind-based projects.
Using Next.js 13 โย I have a file that looks like this:
import { tv } from "tailwind-variants";
type WidthScale = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10;
export const Widths: { [key in WidthScale]: string } = {
0: "w-0",
1: "w-1",
2: "w-2",
3: "w-3",
4: "w-4",
5: "w-5",
6: "w-6",
7: "w-7",
8: "w-8",
9: "w-9",
10: "w-10",
};
export const useWidth = tv(
{
variants: {
width: {
full: "w-full",
...Widths,
},
},
},
{ responsiveVariants: true }
);
When I start the app, I get the following message:
Tailwind Variants Transform Failed: Widths is not defined
If you think this is an issue, please submit it at https://github.com/nextui-org/tailwind-variants/issues/new/choose
If I move the widths directly into the function, the problem goes away โ i.e:
export const useWidth = tv(
{
variants: {
width: {
full: "w-full",
0: "w-0",
1: "w-1",
2: "w-2",
3: "w-3",
4: "w-4",
5: "w-5",
6: "w-6",
7: "w-7",
8: "w-8",
9: "w-9",
10: "w-10",
},
},
},
{ responsiveVariants: true }
);
To Reproduce
Create a file with the above, and reference it inside a component.
Desktop (please complete the following information):
import { tv } from 'tailwind-variants'
const button = tv({
base: "font-medium inline-flex items-center",
variants: {
variant: {
default: "bg-white border hover:bg-gray-50",
filled: "bg-light-primary hover:bg-light-hover-primary text-white",
light: "bg-light-primary/10 hover:bg-light-hover-primary/[0.12] text-light-primary",
outline: "bg-white hover:bg-light-primary/5 border border-light-primary text-light-primary",
subtle: "bg-white hover:bg-light-hover-primary/[0.12] text-light-primary",
transparent: "bg-white text-light-primary",
white: "bg-white hover:bg-gray-50 text-light-primary",
},
size: {
xs: "px-3 h-7 text-xs",
sm: "px-4 h-8 text-sm",
md: "px-5 h-9 text-base",
lg: "px-6 h-10 text-lg",
xl: "px-7 h-11 text-xl",
'2xl': "px-8 h-12 text-xl",
},
radius: {
xs: "rounded-sm",
sm: "rounded",
md: "rounded-md",
lg: "rounded-lg",
xl: "rounded-xl",
'2xl': "rounded-2xl",
full: "rounded-full",
},
fullWidth: {
true: "w-full"
},
},
defaultVariants: {
variant: "filled",
size: "sm",
radius: "sm",
},
});
export default function Button({as, ...props}:any) {
const Component = as || "button";
return (
<>
<Component className={button(props)} {...props}>
{props.children}
</Component>
</>
)
};
Describe the bug
Running command typecheck
failed due to no providing declaration file of utils.js
To Reproduce
typecheck
scriptExpected behavior
Type check must be finished without no errors.
Screenshots
Additional context
You maybe considering allowJS: true
or converting utils.js to TS version.
Describe the bug
compound variants does not support responsive values
To Reproduce
https://stackblitz.com/edit/vite-react-tailwind-dtjgiu?file=src%2FApp.jsx
Describe the bug
Using an arbitrary value that references the theme()
function appears to break the withTV
transformer's ability to generate classes for responsive variants. Example: w-[theme(spacing.32)]
.
To Reproduce
Steps to reproduce the behavior:
App.tsx
on :L23
the large
variant that uses the (valid) arbitrary value syntaxmd:w-[theme(spacing.32)]
) but the CSS is never generated.Expected behavior
CSS is successfully generated for the following classes: md:w-[theme(spacing.32)] md:h-[theme(spacing.32)]
.
Additional context
theme
value like so: w-[calc(theme(spacing.32)_/_2)]
theme()
function as defined and commented out on :L22
appears to work as expected.Describe the bug
This issue appears when I updated typescript from v5.0.4
to v5.1.3
.
now when I run the typecehck tsc --noEmit
I got this error
src/Button.tsx:19:7 - error TS2322: Type 'true' is not assignable to type 'string | number | symbol | never[] | undefined'.
19 disabled: true,
~~~~~~~~
Found 1 error in src/Button.tsx:19
this button component is exactly the live example on the documentation here
To Reproduce
Steps to reproduce the behavior:
pnpm typecheck
Expected behavior
error should not happen
Additional context
Add any other context about the problem here.
Describe the bug
Typescript shows a number of errors
node_modules/tailwind-variants/dist/index.d.ts:216:35 - error TS2344: Type 'V' does not satisfy the constraint 'TVVariantsDefault<S, undefined>'.
Type 'TVVariants<S, B, EV, undefined>' is not assignable to type 'TVVariantsDefault<S, undefined>'.
Type 'TVVariantsDefault<S, B> | { [K in keyof EV]?: { [K2 in keyof EV[K]]?: (S extends TVSlots ? ClassValue | SlotsClassValue<S, B> : ClassValue) | undefined; } | undefined; }' is not assignable to type 'TVVariantsDefault<S, undefined>'.
Type '{ [K in keyof EV]?: { [K2 in keyof EV[K]]?: (S extends TVSlots ? ClassValue | SlotsClassValue<S, B> : ClassValue) | undefined; } | undefined; }' is not assignable to type 'TVVariantsDefault<S, undefined>'.
Type '{ [K2 in keyof EV[K]]?: (S extends TVSlots ? ClassValue | SlotsClassValue<S, B> : ClassValue) | undefined; } | undefined' is not assignable to type '{ [key: string]: S extends TVSlots ? ClassValue | SlotsClassValue<S, undefined> : ClassValue; }'.
Type 'undefined' is not assignable to type '{ [key: string]: S extends TVSlots ? ClassValue | SlotsClassValue<S, undefined> : ClassValue; }'.
Type 'TVVariants<S, B, TVVariants<ES, B, E["variants"], ES>, undefined>' is not assignable to type 'TVVariantsDefault<S, undefined>'.
Type 'TVVariantsDefault<S, B> | { [K in keyof TVVariants<ES, B, E["variants"], ES>]?: { [K2 in keyof TVVariants<ES, B, E["variants"], ES>[K]]?: (S extends TVSlots ? ClassValue | SlotsClassValue<...> : ClassValue) | undefined; } | undefined; }' is not assignable to type 'TVVariantsDefault<S, undefined>'.
Type '{ [K in keyof TVVariants<ES, B, E["variants"], ES>]?: { [K2 in keyof TVVariants<ES, B, E["variants"], ES>[K]]?: (S extends TVSlots ? ClassValue | SlotsClassValue<...> : ClassValue) | undefined; } | undefined; }' is not assignable to type 'TVVariantsDefault<S, undefined>'.
Type '{ [K2 in keyof TVVariants<ES, B, E["variants"], ES>[K]]?: (S extends TVSlots ? ClassValue | SlotsClassValue<S, B> : ClassValue) | undefined; } | undefined' is not assignable to type '{ [key: string]: S extends TVSlots ? ClassValue | SlotsClassValue<S, undefined> : ClassValue; }'.
Type 'undefined' is not assignable to type '{ [key: string]: S extends TVSlots ? ClassValue | SlotsClassValue<S, undefined> : ClassValue; }'.
Type 'TVVariantsDefault<S, B> | { [x: string]: { [x: string]: (S extends TVSlots ? ClassValue | SlotsClassValue<S, B> : ClassValue) | undefined; } | undefined; }' is not assignable to type 'TVVariantsDefault<S, undefined>'.
Type '{ [x: string]: { [x: string]: (S extends TVSlots ? ClassValue | SlotsClassValue<S, B> : ClassValue) | undefined; } | undefined; }' is not assignable to type 'TVVariantsDefault<S, undefined>'.
'string' index signatures are incompatible.
Type '{ [x: string]: (S extends TVSlots ? ClassValue | SlotsClassValue<S, B> : ClassValue) | undefined; } | undefined' is not assignable to type '{ [key: string]: S extends TVSlots ? ClassValue | SlotsClassValue<S, undefined> : ClassValue; }'.
Type 'undefined' is not assignable to type '{ [key: string]: S extends TVSlots ? ClassValue | SlotsClassValue<S, undefined> : ClassValue; }'.
216 CV extends TVCompoundVariants<V, S, B, EV, ES>,
~
node_modules/tailwind-variants/dist/index.d.ts:217:34 - error TS2344: Type 'V' does not satisfy the constraint 'TVVariantsDefault<S, undefined>'.
217 DV extends TVDefaultVariants<V, S, EV, ES>,
~
node_modules/tailwind-variants/dist/index.d.ts:223:7 - error TS2344: Type 'V' does not satisfy the constraint 'TVVariantsDefault<S, undefined>'.
223 V,
~
node_modules/tailwind-variants/dist/index.d.ts:263:39 - error TS2344: Type 'V' does not satisfy the constraint 'TVVariantsDefault<S, undefined>'.
263 compoundSlots?: TVCompoundSlots<V, S, B>;
~
node_modules/tailwind-variants/dist/index.d.ts:275:19 - error TS2344: Type 'V' does not satisfy the constraint 'TVVariantsDefault<S, undefined>'.
275 ): TVReturnType<V, S, B, C, EV, ES, E>;
~
Found 7 errors in 2 files.
To Reproduce
Typescript 4.8.4 use react-aria and tsc
tsconfig:
"compilerOptions": {
"esModuleInterop": true,
"moduleResolution": "node",
"resolveJsonModule": true,
"jsx": "react-jsx",
"target": "ES2019",
"module": "ES2022",
"strict": true,
"allowJs": true,
}
Expected behavior
Not have typescript errors
Additional context
Add any other context about the problem here.
I am try to pass an array of string inside of property on compoundSlots similar with happen with compoundVariants
const foo = tv({
slots: {
base: "flex flex-wrap",
cursor: ["absolute", "flex", "overflow-visible"],
},
variants: {
size: {
xs: {},
sm: {},
md: {},
lg: {},
xl: {},
},
},
compoundSlots: [
{
slots: ["base"],
size: ["xs", "lg"],
class: "w-7 h-7 text-xs",
}
],
})
[]);
const { base } = foo({size: 'xs'});
**HTML**
<div class={base()}>
</div>
Expected behavior
**HTML**
<div class="flex flex-wrap w-7 h-7 text-xs">
</div>
The properties inside of compoundSlots are hoping 2 differences types string and string[], but when put array of string stop to working. This example, i am using size. When size is 'xs' or 'lg' it need to add the classes. Like compoundVariants working.
Example:
compoundSlots: [
{
slots: ["base"],
size: ["xs", "lg"],
class: "w-7 h-7 text-xs",
}
]
Now, i don't know if above quote is a bug or feature, but i hope some answers
Hey all! some time ago I started an open-source project called Nullwind, it's a components system that uses Tailwind. We're willing to use Tailwind Variants but miss some features described below.
in our case, we have a button with different colors, and this same button has a prop called outline
which applies outline styles following the chosen color. for example:
<Button color="secondary" outline />
to achieve it, we needed to create something like the following:
const button = tv({
variants: {
color: {
primary:
"text-white bg-primary-500 border border-transparent hover:bg-primary-800 disabled:hover:bg-primary-500",
},
outline: {
primary:
"text-primary-500 bg-white border border-primary-500 hover:bg-primary-50 disabled:hover:bg-white",
},
}
})
const Button = ({ color, outline, class: klass }) => {
<button
class={button({
color,
...(outline && { outline: color }),
class: klass,
})}
>Click here!</button>
}
after doing that, I noticed the outline
type is being mistyped. is there any other way to achieve what we're looking for?
In our framework, the user is able to style the components globally, locally, or via class. check here
[baseTheme, globalTheme, localTheme, class]
we were able to achieve it but needed to create a complex logic that merges these objects. it'd be cool if we had any way to extend multiple themes, so we can use the TV engine to replace all the necessary properties correctly.
our workaround:
const button = tv({ extend: buttonTheme, ...mergeThemes(context.theme, props.theme)?.button });
button({ ...props, class: props.class })
suggestion:
const button = tv({ extend: [buttonTheme, tv(context.theme.button), tv(props.theme.button)] });
button({ ...props, class: props.class })
I'd love to discuss more about these requested features ๐
We are using react-aria-components in our component library and one thing we find that tailwind-variants doesn't support very well is the ability to override variants at the slot level. For example, with react-aria-components, some variables used for variants are passed to the class name prop like shown below.
const tooltipStyles = tv({ ... })
const styles = tooltipStyles()
<BaseTooltip className={({ placement }) => styles.base({ placement })}>
<OverlayArrow className={({ placement }) => styles.arrow({ placement })}>
<svg />
</OverlayArrow>
{content}
</BaseTooltip>
While this is more of a niche use case, and defining the variants at the top level is definitely the more likely case, having the ability to at least override variants at the slot level to support this use case would be nice.
Thoughts?
Describe the bug
I am using TV to style my button component
and I have a rounded variant, rounded variant by default is md
in defaultVariants
when I tried to add a class name rounded-0
to override the base class, the classes did not get merged and both of the classes are on the component when I tried to add a class name to override the color variant by adding new class, the classes got merged and the background color on the component is what I passed from className
<Button
variant="solid"
color="danger"
className="rounded-0 bg-secondary text-danger hover:bg-secondary-700"
>
Custom
</Button>
Expected behavior
it should override the base class with the given class in className
I would like to use the Tailwind CSS "Arbitrary values" in variants and slots, but I couldn't figure out how to write it. Is there any documents or reference code?
const styles = tv({
variants: {
focusable: {
true: 'some-classes',
},
tabbable: {
true: 'some-classes',
},
},
compoundVariants: [
{
focusable: true,
tabbable: true,
className: `max-h-[${someArbitaryValue}]`,
},
],
})
// Can you pass `someArbitaryValue` to styled?
<SomeComponent className={styles({ focusable, tabbable })} />
I couldn't figure it out from the documents so I surpassed it by writing the following.
const styles = tv({...})
const maxHeightStyle = focusable && tabbable ? `max-h-[${someArbitaryValue}]` : ''
<div className={`${styles(...)} ${maxHeightStyle}`} />
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.