Introduction#
GitHub this note show
- React Ref and UseRef
- Create a re-useable react component
- Getting started with Radix-UI
Ref and UseRef#
Let creaet input and expose ref to its parent
interface MyInputProps extends React.InputHTMLAttributes<HTMLInputElement> {label: string;}const MyInput = forwardRef<HTMLInputElement, MyInputProps>(function MyInput({ label, ...props },ref) {return (<label htmlFor="first_name">{label}<input ref={ref}></input></label>);});
Then create a Page in /blog/page.tsx
const BookPage = () => {const ref = useRef<HTMLInputElement>(null);function handleClick() {if (ref.current) {ref.current.focus();}}return (<div className="grid gap-6 mb-6 grid-cols-1"><MyInput ref={ref} label="First Name"></MyInput><buttonclassName="bg-green-500 px-10 py-3 rounded-sm"onClick={handleClick}>Edit</button></div>);};export default BookPage;
Reusesable Component#
First we need to install some packages
npm install clsx, tailwind-merge, class-variance-authority
Second, let create a button component
import { cva, type VariantProps } from "class-variance-authority";import { clsx, type ClassValue } from "clsx";import React from "react";import { twMerge } from "tailwind-merge";function cn(...inputs: ClassValue[]) {return twMerge(clsx(inputs));}const buttonVariants = cva("...", {variants: {variant: {default:"bg-primary text-primary-foreground shadow-md hover:bg-primary/90",destructive:"bg-destructive text-destructive-foreground hover:bg-destructive/90",outline:"border border-input hover:bg-accent hover:text-accent-foreground",secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",ghost: "shadow-none hover:bg-accent hover:text-accent-foreground",link: "text-primary underline-offset-4 shadow-none hover:underline",},size: {default: "h-8 px-4 py-2",sm: "h-8 rounded-md px-3",lg: "h-11 rounded-md px-8",icon: "h-8 w-8 p-0",},},defaultVariants: {variant: "default",size: "default",},});export interface ButtonPropsextends React.ButtonHTMLAttributes<HTMLButtonElement>,VariantProps<typeof buttonVariants> {asChild?: boolean;}const MyButton = React.forwardRef<HTMLButtonElement, ButtonProps>(({ className, variant, size, asChild = false, ...props }, ref) => {return (<buttonclassName={cn(buttonVariants({ variant, size, className }))}ref={ref}{...props}>Hello Button</button>);});MyButton.displayName = "MyButton";export default MyButton;
Finally, we can use the MyButton somewhere else
<MyButton variant={"outline"} size={"lg"} className="bg-orange-500"></MyButton>
Radix-UI#
To get started with Radix-UI, let create a Dialog component. Here is the basic structure
<Dialog.Root><Dialog.Trigger className="rounded p-2 hover:bg-gray-200"><Pencil1Icon /></Dialog.Trigger><Dialog.Portal><Dialog.Overlay className="fixed inset-0 bg-black/50" /><Dialog.Content><div><Dialog.Title></Dialog.Title><Dialog.Close></Dialog.Close></div><div><UserFields user={user} /></div><div><Dialog.Close></Dialog.Close></div></Dialog.Content></Dialog.Portal></Dialog.Root>
Full implementation
export default function Page() {return (<div className="py-10"><div className="mx-auto max-w-sm space-y-4 rounded-lg bg-gray-200 p-4">{users.map((user) => (<divclassName="flex justify-between rounded-lg bg-white px-4 py-4 text-gray-900 shadow"key={user.id}><div><p>{user.name}</p><p className="text-sm text-gray-500">{user.role}</p><p className="text-sm text-gray-500">{user.email}</p></div><div><Dialog.Root><Dialog.Trigger className="rounded p-2 hover:bg-gray-200"><Pencil1Icon /></Dialog.Trigger><Dialog.Portal><Dialog.Overlay className="fixed inset-0 bg-black/50" /><Dialog.Content className="fixed left-1/2 top-1/2 w-full max-w-md -translate-x-1/2 -translate-y-1/2 rounded-md bg-white p-8 text-gray-900 shadow"><div className="flex items-center justify-between"><Dialog.Title className="text-xl">Edit contact</Dialog.Title><Dialog.Close className="text-gray-400 hover:text-gray-500"><Cross1Icon /></Dialog.Close></div><div className="mt-8"><UserFields user={user} /></div><div className="mt-8 space-x-6 text-right"><Dialog.Close className="rounded px-4 py-2 text-sm font-medium text-gray-500 hover:text-gray-600">Cancel</Dialog.Close><button className="rounded bg-green-500 px-4 py-2 text-sm font-medium text-white hover:bg-green-600">Save</button></div></Dialog.Content></Dialog.Portal></Dialog.Root></div></div>))}</div></div>);}