skip to Main Content

I have a component that has a dynamic tag name which can be either div or fieldset depending on the value of the group prop that’s returned from our useForm hook.

const FormGroup = React.forwardRef<
  HTMLFieldSetElement | HTMLDivElement,
  React.HTMLAttributes<HTMLFieldSetElement | HTMLDivElement>
>(({ children, className, ...props }, ref) => {
  const { group } = useForm();
  const Component = group ? "fieldset" : "div";

  return (
    <Component ref={ref} className={className} {...props}>
      {children}
    </Component>
  );
});

However it returns an error that ref is not assignable… I tried using:

const Component = group ? "fieldset" : "div" as keyof JSX.IntrinsicElements;

Is there a clean way to type check a dynamic tag name that’s using a ref?

2

Answers


  1. You can use conditional types and a type assertion to ensure the correct typing.

    import React from 'react';
    
    type FormGroupProps = React.HTMLAttributes<HTMLFieldSetElement | HTMLDivElement>;
    
    const FormGroup: React.ForwardRefRenderFunction<HTMLFieldSetElement | HTMLDivElement, FormGroupProps> = (
      { children, className, ...props },
      ref
    ) => {
      const { group } = useForm();
    
      const Component = group ? 'fieldset' : 'div';
    
      return (
        <Component ref={ref as React.MutableRefObject<HTMLFieldSetElement | HTMLDivElement>} className={className} {...props}>
          {children}
        </Component>
      );
    };
    
    export default React.forwardRef(FormGroup);
    
    Login or Signup to reply.
  2. This is my approach

    
    import {
      ElementType,
      FC,
      HTMLAttributes,
      Ref,
      forwardRef,
      useRef,
    } from "react";
    
    interface ComponentProps extends HTMLAttributes<HTMLElement> {
      as?: ElementType;
      ref: Ref<HTMLElement>;
    }
    
    const Component: FC<ComponentProps> = forwardRef(
      ({ as: Tag = "div", children, ...otherProps }, ref) => {
        return (
          <Tag {...otherProps} ref={ref}>
            {children}
          </Tag>
        );
      }
    );
    
    const App: FC = () => {
      const myRef = useRef<HTMLElement>(null);
      const group: "div" | "fieldset" = "div";
      return (
        <>
          <div>App</div>
          <Component as={group} ref={myRef}>
            <p>This is the component's content</p>
          </Component>
        </>
      );
    };
    
    export default App;
    
    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search