Icons
SVG icons built on a shared IconBase component. Sized to 1em by default so they scale with text.
| Prop | Type | Default |
|---|---|---|
| size | 3 | 4 | 5 | 6 | 8 | 10 | 12 | — |
| className | string | — |
| aria-hidden | boolean | "true" | "false" | true |
ArrowBack
ArrowForward
Check
Close
ContentCopy
DarkMode
Favorite
Info
KeyboardArrowDown
KeyboardArrowLeft
KeyboardArrowRight
KeyboardArrowUp
LightMode
Link
Menu
NorthEast
Share
import { MenuIcon, CloseIcon, ShareIcon } from "@/ui/icons";
<MenuIcon />
<CloseIcon />
<ShareIcon /><InfoIcon size={3} />
<InfoIcon size={4} />
<InfoIcon size={5} />
<InfoIcon size={6} />
<InfoIcon size={8} />
<InfoIcon size={10} />
<InfoIcon size={12} />- Icons default to 1em so they scale with the parent font size. Use the size prop for explicit sizing.
- Always import from @/ui/icons, not from individual files.
- Icons are aria-hidden by default. For standalone meaningful icons, use IconBase with a title prop instead.
import { MenuIcon } from "@/ui/icons";
<MenuIcon />src/ui/icons/IconBase.tsx
import { cn } from "@/utils";
type IconSize = 3 | 4 | 5 | 6 | 8 | 10 | 12;
interface IconProps {
className?: string;
size?: IconSize;
"aria-hidden"?: boolean | "true" | "false";
}
interface IconBaseProps extends IconProps {
children: React.ReactNode;
viewBox?: string;
fill?: string;
stroke?: string;
title?: string;
}
const sizeMap: Record<IconSize, string> = {
3: "h-3 w-3",
4: "h-4 w-4",
5: "h-5 w-5",
6: "h-6 w-6",
8: "h-8 w-8",
10: "h-10 w-10",
12: "h-12 w-12",
};
export function IconBase({
className,
"aria-hidden": ariaHidden = true,
children,
viewBox = "0 -960 960 960",
fill = "currentColor",
size,
stroke,
title,
}: IconBaseProps) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox={viewBox}
fill={fill}
stroke={stroke}
focusable="false"
role={title ? "img" : undefined}
aria-hidden={title ? undefined : ariaHidden}
className={cn(
size !== undefined ? sizeMap[size] : "h-[1em] w-[1em]",
"shrink-0",
className,
)}
>
{title && <title>{title}</title>}
{children}
</svg>
);
}