Comments (6)
@kripod thanks, I really appreciate the response. If there's any chance you could just write down 1-3 quick bullet points here on your motivation for moving away from the as
prop, I would appreciate it tremendously. To me, render props seem like the best type-safe alternative to the as
prop, but I have to admit that I don't fully understand why everyone is "breaking up with the as
prop", so to speak, in the first place. At the same time, I have high-impact architectural decisions to make regarding v2 of a component library and am trying to eliminate as many potential blind spots for myself as possible. Either way, thanks again: Your efforts here have helped me out a lot over the past couple of years.
from react-polymorphic-box.
Apologies for my late response.
The main reason I’d go with a render prop is that the props passed to the rendered element should be mapped in most cases. For instance, while a polymorphic Button
component may have a disabled
prop that can be passed to a <button>
element, the same prop can’t be passed to an <a>
. Therefore, we have to map the props to be passable to <a>
as shown above.
Also, the reason I haven’t adopted the Slot
approach of Radix UI is that sometimes, a polymorphic component may want to modify the children
it passes for rendering. E.g. instead of just rendering the children
retrieved from the outside, <Button disabled="loading">
may render <span className={/* … */}>{children} <Spinner /></span>
instead of just the original children
. The same behavior applies to making ButtonProps["children"]
a render prop: we can’t extend children
with a spinner when doing that.
from react-polymorphic-box.
Additional info that may or may not be relevant;
React: 18.2.0 (types: 18.2.8)
React DOM: 18.2.0 (types: 18.2.4)
Typescript: 5.0.4
from react-polymorphic-box.
Thank you for reporting.
Unfortunately, I wouldn’t recommend using either this project or react-polymorphic-types anymore.
I’d suggest specifying a render
prop instead of as
as follows:
import clsx from "clsx";
import * as React from "react";
export type ButtonProps = React.ComponentPropsWithRef<"button"> & {
render?: (
props: React.ComponentPropsWithoutRef<"button"> &
Required<
Pick<
React.ComponentPropsWithoutRef<"button">,
"disabled" | "className" | "children"
>
>,
) => React.ReactNode;
};
export const Button = React.forwardRef(function Button(
{ disabled, className, children = null, render, ...restProps }: ButtonProps,
ref: React.ForwardedRef<HTMLButtonElement>,
) {
return (
<>
{(render ?? ((props) => <button ref={ref} type="button" {...props} />))({
disabled: Boolean(disabled),
className: clsx(
/* Base class names may be added here */
className,
),
children,
...restProps,
})}
</>
);
});
Usage:
<Button
render={renderButtonAsLink(({ className, children }) => (
<a href="#_" className={className}>
{children}
</a>
))}
>
Click me
</Button>
function renderButtonAsLink(
render: (
props: React.ComponentPropsWithoutRef<"button"> &
Required<
Pick<React.ComponentPropsWithoutRef<"button">, "className" | "children">
>,
) => React.ReactNode,
) {
return (({ disabled, className, children, ...restProps }) =>
disabled ? (
// https://www.scottohara.me/blog/2021/05/28/disabled-links.html
// eslint-disable-next-line jsx-a11y/anchor-is-valid
<a role="link" aria-disabled className={className}>
{children}
</a>
) : (
render({ disabled, className, children, ...restProps })
)) satisfies ButtonProps["render"];
}
from react-polymorphic-box.
@kripod thanks for your past work on react-polymorphic-box and for the update regarding render props. Would you happen to be able to link me to any reference material (such as a blog post) that would explain your particular implementation of render props further?
from react-polymorphic-box.
@nsaunders Unfortunately, I don’t really find the time to create a blog, even though I could write quite a bit about the topic. I’m not aware of any articles mentioning render props to solve polymorphism.
from react-polymorphic-box.
Related Issues (14)
- Unable to built Next.js since upgrading to v2 HOT 6
- Function types are typed as any HOT 3
- picking `ref` from component's props is not allowed HOT 8
- jest failed when testing a component that use HOT 5
- Best approach to creating a hierarchy of components HOT 1
- Edge case with ref forwarding doesn't throw an error when needed
- "string" is not assignable to type '"as"' HOT 1
- displayName and propTypes are not allowed on forwardRef component HOT 3
- Incorrect work with Unions Types HOT 2
- Type error with TypeScript 5.2.2 HOT 1
- Suggestion: PolymorphicComponent type HOT 1
- Missing Types on PolymorphicComponent HOT 1
- Target ES5 instead of ES2020 HOT 6
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from react-polymorphic-box.