Utility
mergeProps
mergeProps
can be used when you want to apply a specific tailwind
property to a style.
api reference,
mergeProps
When to use?
For example, let's say you've created a common container component called Box
.
What you want to do is dynamically change only the borderColor
property of the box, while maintaining the unique style you've defined for the Box.
So you create a borderColor
props for Box
component and add the desired color, and it's applied.
import { tw, type Tailwind } from "~/tw"
const box = tw.style({
display: "flex",
alignItems: "items-center",
borderWidth: "border",
borderColor: "border-blue-300",
// more box styles here...
})
interface BoxProps {
children: React.ReactNode
borderColor?: Tailwind["borderColor"]
}
export const Box = ({ children, borderColor }: BoxProps) => {
// ass borderColor as props
return <div className={`${box.class} ${borderColor}`}>{children}</div>
}
Now you're thinking, "I can perfectly apply any borderColor
with types.".
In most cases, you'll see that it works perfectly, but in some cases, it doesn't.
// border color is red-300
const Works = () => <Box borderColor="border-red-300">love</Box>
// border color is not gray-100
const NotWorks = () => <Box borderColor="border-gray-100">love</Box>
Problem
This happens because the order of border-color
property in the css
file generated by tailwind
doesn't work as you wrote it down: in the className
of the Box, borderColor
is obviously last, but in the generated css
, it's not last.
The order of the css
is generated in the order predefined by the tailwind
framework, so it doesn't work as expected.
/* ... */
.border-gray-100 {
border-color: "~100";
}
/* ... */
.border-blue-300 {
border-color: "~300";
}
/* ... */
.border-red-300 {
border-color: "~300";
}
/* ... */
A: Merging properties
The solution is simple. If the borderColor
props are passed, clear the predefined border-blue-300
property, and if not, keep it.
This is where mergeProps
comes in. Unlike regular tailwind
, tailwindest uses an object
, so it has a key
, which means we can just overwrite the value with the same key and be done with it.
import { tw, type Tailwind } from "@/tw"
const box = tw.style({
display: "flex",
alignItems: "items-center",
borderWidth: "border",
borderColor: "border-blue-300",
// more box styles here...
})
interface BoxProps {
children: React.ReactNode
borderColor?: Tailwind["borderColor"]
}
export const Box = ({ children, borderColor }: BoxProps) => {
// ass borderColor as props
return (
<div
className={mergeProps(box.style, {
borderColor,
})}
>
{children}
</div>
)
}
B: Merging styleSheets
Or just merge all the styles with your Tailwindest
type.
interface UniversalTextProps {
children: React.ReactNode
tw?: Tailwindest
}
const UniversalText = ({ children, tw }: UniversalTextProps) => (
<p
className={tw.mergeProps(
text.style,
tw // override new styleSheet
)}
>
{children}
</p>
)
Now UniversalText
is fully customizable via tw
props.
const Some = (
<UniversalText
tw={{
fontFamily: "font-mono",
}}
>
It is UniversalText
</UniversalText>
)
In this way, you don't need to install classname merging packages like tailwind-merge
.