Last active
December 6, 2022 23:30
-
-
Save ja-k-e/ee71e4857fc20a56b5cf8ed731100a0b to your computer and use it in GitHub Desktop.
ChatGPT sequence creating an accessible button component
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
create an accessible button component using react and typescript with | |
variant, size, element, aria label, and optional href props | |
*/ | |
import React, { ButtonHTMLAttributes } from "react"; | |
type ButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & { | |
variant?: "primary" | "secondary" | "tertiary"; | |
size?: "small" | "medium" | "large"; | |
element?: "button" | "a"; | |
ariaLabel: string; | |
href?: string; | |
}; | |
const Button: React.FC<ButtonProps> = ({ | |
variant = "primary", | |
size = "medium", | |
element = "button", | |
ariaLabel, | |
href, | |
children, | |
...rest | |
}) => { | |
const Element = element === "a" ? "a" : "button"; | |
return ( | |
<Element | |
href={Element === "a" ? href : undefined} | |
aria-label={ariaLabel} | |
className={`button button--${variant} button--${size}`} | |
{...rest} | |
> | |
{children} | |
</Element> | |
); | |
}; | |
export default Button; | |
/* | |
use a discriminated union so that when the element prop is a, href | |
is required and onclick is optional. | |
when the element prop is button, make the onclick required and href undefined. | |
*/ | |
import React, { ButtonHTMLAttributes } from "react"; | |
type ButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & { | |
variant?: "primary" | "secondary" | "tertiary"; | |
size?: "small" | "medium" | "large"; | |
element: "button" | "a"; | |
ariaLabel: string; | |
}; | |
type ButtonAnchorProps = { | |
element: "a"; | |
href: string; | |
}; | |
type ButtonButtonProps = { | |
element: "button"; | |
onClick: () => void; | |
}; | |
type Props = ButtonProps & (ButtonAnchorProps | ButtonButtonProps); | |
const Button: React.FC<Props> = ({ | |
variant = "primary", | |
size = "medium", | |
element, | |
ariaLabel, | |
href, | |
onClick, | |
children, | |
...rest | |
}) => { | |
const Element = element === "a" ? "a" : "button"; | |
return ( | |
<Element | |
href={Element === "a" ? href : undefined} | |
onClick={Element === "button" ? onClick : undefined} | |
aria-label={ariaLabel} | |
className={`button button--${variant} button--${size}`} | |
{...rest} | |
> | |
{children} | |
</Element> | |
); | |
}; | |
export default Button; | |
/* great. now make the aria label optional */ | |
import React, { ButtonHTMLAttributes } from "react"; | |
type ButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & { | |
variant?: "primary" | "secondary" | "tertiary"; | |
size?: "small" | "medium" | "large"; | |
element: "button" | "a"; | |
ariaLabel?: string; | |
}; | |
type ButtonAnchorProps = { | |
element: "a"; | |
href: string; | |
}; | |
type ButtonButtonProps = { | |
element: "button"; | |
onClick: () => void; | |
}; | |
type Props = ButtonProps & (ButtonAnchorProps | ButtonButtonProps); | |
const Button: React.FC<Props> = ({ | |
variant = "primary", | |
size = "medium", | |
element, | |
ariaLabel, | |
href, | |
onClick, | |
children, | |
...rest | |
}) => { | |
const Element = element === "a" ? "a" : "button"; | |
return ( | |
<Element | |
href={Element === "a" ? href : undefined} | |
onClick={Element === "button" ? onClick : undefined} | |
aria-label={ariaLabel} | |
className={`button button--${variant} button--${size}`} | |
{...rest} | |
> | |
{children} | |
</Element> | |
); | |
}; | |
export default Button; | |
/* | |
remove the html attributes from the button props | |
*/ | |
import React from "react"; | |
type ButtonProps = { | |
variant?: "primary" | "secondary" | "tertiary"; | |
size?: "small" | "medium" | "large"; | |
element: "button" | "a"; | |
ariaLabel?: string; | |
}; | |
type ButtonAnchorProps = { | |
element: "a"; | |
href: string; | |
}; | |
type ButtonButtonProps = { | |
element: "button"; | |
onClick: () => void; | |
}; | |
type Props = ButtonProps & (ButtonAnchorProps | ButtonButtonProps); | |
const Button: React.FC<Props> = ({ | |
variant = "primary", | |
size = "medium", | |
element, | |
ariaLabel, | |
href, | |
onClick, | |
children, | |
...rest | |
}) => { | |
const Element = element === "a" ? "a" : "button"; | |
return ( | |
<Element | |
href={Element === "a" ? href : undefined} | |
onClick={Element === "button" ? onClick : undefined} | |
aria-label={ariaLabel} | |
className={`button button--${variant} button--${size}`} | |
{...rest} | |
> | |
{children} | |
</Element> | |
); | |
}; | |
export default Button; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment