Skip to content

Instantly share code, notes, and snippets.

@serifcolakel
Created December 6, 2023 20:05
Show Gist options
  • Save serifcolakel/9204e60bc4a401217a5b49ebfa79c07a to your computer and use it in GitHub Desktop.
Save serifcolakel/9204e60bc4a401217a5b49ebfa79c07a to your computer and use it in GitHub Desktop.
These form elements can include buttons, links, inputs, selects, and text areas, each with various styling options. Instead of creating separate components for each form element, we can build a polymorphic React FormElement component.
import React from 'react';
type FormElementBaseProps = {
children?: React.ReactNode;
variant?: 'primary' | 'secondary' | 'outline' | 'link';
};
type FormElementProps = FormElementBaseProps &
(
| (React.ButtonHTMLAttributes<HTMLButtonElement> & {
as: 'button';
})
| (React.AnchorHTMLAttributes<HTMLAnchorElement> & {
as: 'a';
})
| (React.InputHTMLAttributes<HTMLInputElement> & {
as: 'input';
})
| (React.SelectHTMLAttributes<HTMLSelectElement> & {
as: 'select';
})
| (React.TextareaHTMLAttributes<HTMLTextAreaElement> & {
as: 'textarea';
})
);
export function FormElement({ variant, ...props }: FormElementProps) {
switch (props.as) {
case 'button':
return <button {...props}>{props.children}</button>;
case 'a':
return <a {...props}>{props.children}</a>;
case 'input':
return <input {...props} />;
case 'select':
return <select {...props}>{props.children}</select>;
case 'textarea':
return <textarea {...props} />;
default:
return null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment