Customize `className` with props from underlying component `className` render function.
izznat opened this issue ยท 8 comments
๐ Feature Proposal
Some components from react-aria-components
accept a function as className
prop value. The function will receive the render props. So, it basically a render function for className
. react-twc
supports customizing className
via props, might as well merge className
render props from such components with the transient props. I use this pattern a lot while wrapping react-aria-components
.
Motivation
To properly customize the produced className
using the underlying className
render props.
Example
Without react-twc
:
import * as React from 'react'
import * as RAC from 'react-aria-components'
import { twMerge as tw } from 'tailwind-merge'
const Button = React.forwardRef(function Button({ className, ...props }, ref) {
return (
<RAC.Button
{...props}
className={(renderProps) => {
return tw('flex px-2', typeof className === 'function' ? className(renderProps) : className)
}
} />
)
})
With react-twc
:
import * as RAC from 'react-aria-components'
import { twc } from 'react-twc'
const Button = twc(RAC.Button)(
(props) => ['flex px-2', props.isHovered ? 'bg-blue-700' : 'bg-blue-600'], { asFunction: true }
)
Pitch
By supporting classname
render function, react-twc
will be fully compatible with component library such as react-aria-components
and headlessui
.
The problem is how react-twc
can decide to pass in either a function or a string to the underlying component. We might need to add an option for that'
Hello @izznatsir, good idea, I think we can make something to be usable with these libraries. I could take a look, feel free to submit a PR anyway. Keep it minds that it is not the main use-case and the library should be as a light as possible.
I've updated the description with the proposed API. I'll try to submit a PR later.
FYI, there's a function in React Aria Components for this. Haven't had time to add to the docs yet (was added very last minute).
import {composeRenderProps} from 'react-aria-components';
<RACButton className={composeRenderProps(props.className, className => twMerge('...', className))} />
@devongovett do you have suggestion of an API to fully support react-aria-components in twc
?
As I understand it should be possible to return a function as a className, so this should work right?
const Button = twc(RACButton )(props => renderProps => ['flex px-2', renderProps.isHovered ? 'bg-blue-700' : 'bg-blue-600']);
As I understand it should be possible to return a function as a className, so this should work right?
const Button = twc(RACButton )(props => renderProps => ['flex px-2', renderProps.isHovered ? 'bg-blue-700' : 'bg-blue-600']);
Actually, it won't work. Because, the renderProps is received at component render time instead of template creation time. renderProps => ['flex px-2', renderProps.isHovered ? 'bg-blue-700' : 'bg-blue-600'])
will be passed to the compose function instead of the component className props, which don't have access to the renderProps.
To support this pattern, the className evaluation needs to executed at component render time by passing in a render function to the className prop instead of template creation time.
But, I realized that react-aria-components
also exposes data-[...]
attributes. So, it can be easily accessed via data-[...]:
variant or using tailwindcss-react-aria-components
plugin.
So, this feature is not required to works with headless ui lib such as react-aria-components
. But, the end user of the component cannot provides a render function as the className prop.
@izznatsir I just submitted a PR #20, could you take a look? ๐