Implement "as" prop in React component in TypeScript

Viewed 1339

I'm implementing a generic component which accept as prop as any HTML element in TypeScript.

<Component as='div' {...myProps} {...divProps} />

<Component as='button' {...myProps} {...buttonProps} />

I just get lost while trying to define my component's prop as any HTML element.

Please share your advice.

Thanks.

3 Answers

Use somthing like this:

interface IProps {
  as: React.ElementType;
}
export const Component = (props: IProps) => {
  const { as: Cmp = "div", ...rest } = props;

  return <Cmp {...rest} />;
};

The following article describes building a strongly typed polymorphic component.

Here is a summary of how to do it. The critical point is to use 2 generic types provided by react, these types are ElementType and ComponentPropsWithoutRef. ElementType represents a valid React Component or HTMLElement, ComponentPropsWithoutRef can infer the props of Component or an element.

import type { ElementType, ComponentPropsWithoutRef, PropsWithChildren } from "react";

type PolymorphicAsProp<E extends ElementType> = {
  as?: E;
};

type PolymorphicProps<E extends ElementType> = PropsWithChildren<
  ComponentPropsWithoutRef<E>
  & PolymorphicAsProp<E>
>;

const defaultElement = "p";

type TextProps<E extends ElementType = typeof defaultElement> = PolymorphicProps<E> & {
  color?: "primary" | "secondary";
};

function Text<E extends ElementType = typeof defaultElement>({
  as,
  children,
  color = "primary",
  className,
  ...restProps
}: PolymorphicProps<E>) {
  
  const Component = as ?? defaultElement;

  const colorClassName = getColorClassNames(color);

  return (
    <Component
    {...restProps}
    className={[
      className ?? ",
      colorClassName
    ]}>
      {children}
    </Component>
  );
}

Here is a great article about how to do it properly

Related