Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Customize className with props from underlying component className render function. #11

Closed
izznatsir opened this issue Dec 22, 2023 · 8 comments · Fixed by #20
Closed
Labels
enhancement New feature or request

Comments

@izznatsir
Copy link

izznatsir commented Dec 22, 2023

🚀 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.

@izznatsir
Copy link
Author

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'

@izznatsir izznatsir changed the title Customize className with props from underlying component className render function. Customize className with props from underlying component className render function. Dec 22, 2023
@gregberge
Copy link
Owner

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.

@gregberge gregberge added the enhancement New feature or request label Dec 22, 2023
@izznatsir
Copy link
Author

I've updated the description with the proposed API. I'll try to submit a PR later.

@devongovett
Copy link

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))} />

@gregberge
Copy link
Owner

@devongovett do you have suggestion of an API to fully support react-aria-components in twc?

@gregberge
Copy link
Owner

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']);

@izznatsir
Copy link
Author

izznatsir commented Dec 23, 2023

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.

@gregberge
Copy link
Owner

@izznatsir I just submitted a PR #20, could you take a look? 👀

gregberge added a commit that referenced this issue Dec 24, 2023
gregberge added a commit that referenced this issue Dec 24, 2023
gregberge added a commit that referenced this issue Dec 24, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants