Skip to content

Instantly share code, notes, and snippets.

@ja-k-e
Last active December 6, 2022 23:30
Show Gist options
  • Save ja-k-e/ee71e4857fc20a56b5cf8ed731100a0b to your computer and use it in GitHub Desktop.
Save ja-k-e/ee71e4857fc20a56b5cf8ed731100a0b to your computer and use it in GitHub Desktop.
ChatGPT sequence creating an accessible button component
/*
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