Code Monkey home page Code Monkey logo

Comments (6)

nsaunders avatar nsaunders commented on June 14, 2024 1

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

kripod avatar kripod commented on June 14, 2024 1

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.

mogusbi-motech avatar mogusbi-motech commented on June 14, 2024

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.

kripod avatar kripod commented on June 14, 2024

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.

nsaunders avatar nsaunders commented on June 14, 2024

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

kripod avatar kripod commented on June 14, 2024

@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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.