Peter Mekhaeil

Overriding HTML Attributes in React TypeScript

First extend the native HTML attributes:

interface MyInputProps extends React.HTMLProps<HTMLInputElement> {
  size: "sm" | "md" | "lg";
}

A typescript will appear because TS knows that HTMLInputElement already has a size attribute and it does not match the one we added:

interface MyInputProps extends React.HTMLProps<HTMLInputElement> {
  size: "sm" | "md" | "lg";
// ^? Type 'string' is not assignable to type 'number'
}

We need to omit the native size attribute:

interface MyInputProps extends Omit<React.HTMLProps<HTMLInputElement>, 'size'> {
  size: "sm" | "md" | "lg";
}

And now we can type our new component. Spread the props so our new size prop is not set as the value to the native HTML attribute.

const MyInput: React.FC<MyInputProps> = (props) => {
  const { size, ...rest } = props;
  return <input {...rest} className="my-input" />;
};

If we want to continue using the native size, Chakra UI has a clever technique of using a new prop htmlSize that can be used instead:

interface MyInputProps extends Omit<React.HTMLProps<HTMLInputElement>, 'size'> {
  size: "sm" | "md" | "lg";
  htmlSize?: number;
}

const MyInput: React.FC<MyInputProps> = (props) => {
  const { size, htmlSize, ...rest } = props;
  return <input {...rest} size={htmlSize} className="my-input" />;
};