Components · Display
Icons
Twenty-four icons on a 16px grid with a 1.5px stroke, decorative unless labelled.
0.39% of the 2,062 sites in The UI Index have a icon (8 sites).
- arrow-right
- arrow-up-right
- check
- x
- plus
- minus
- chevron-down
- chevron-right
- chevron-left
- search
- menu
- copy
- play
- map-pin
- calendar
- settings
- user
- bell
- trash
- edit
- download
- info
- alert
- arrow-right
- arrow-up-right
- check
- x
- plus
- minus
- chevron-down
- chevron-right
- chevron-left
- search
- menu
- copy
- play
- map-pin
- calendar
- settings
- user
- bell
- trash
- edit
- download
- info
- alert
Both previews render the same markup; the HTML tab below is that markup without a framework.
Install
- React
- npx shadcn@
latest add https:// www.themes.dev/ caseroom/ r/ icon.json - Astro
- npx shadcn@
latest add https:// www.themes.dev/ caseroom/ r/ astro/ icon.json
Or copy the files below into your project. They need clsx, tailwind-merge, and the Caseroom theme. The HTML needs only the compiled CSS.
import { cn } from '@/lib/utils';
import { ICONS, iconClasses, type IconName } from './icon.variants';
export { ICONS, type IconName };
export interface IconProps {
name: IconName;
/** Only when the icon means something on its own; otherwise it is hidden from screen readers. */
label?: string;
className?: string;
}
/** One of Caseroom's icons: 16px grid, 1.5px stroke, decorative unless it has a label. */
export function Icon({ name, label, className }: IconProps) {
return (
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" role={label ? 'img' : undefined} aria-label={label} aria-hidden={label ? undefined : 'true'} className={cn(iconClasses, className)}>
<path d={ICONS[name]} />
</svg>
);
}/** Caseroom's icons: drawn on a 16px grid with a 1.5px stroke, round caps and joins, so they sit with the text.
* Decorative by default (aria-hidden); give a label when the icon is the only content of a control or carries
* meaning. Sizes follow the text: 16px with text-sm, 20px for larger controls. */
export const ICONS = {
'arrow-right': 'M3 8h10M9 4l4 4-4 4',
'arrow-up-right': 'M5 11l6-6M6 5h5v5',
check: 'M3.5 8.5l3 3 6-7',
x: 'M4 4l8 8M12 4l-8 8',
plus: 'M8 3v10M3 8h10',
minus: 'M3.5 8h9',
'chevron-down': 'M4 6l4 4 4-4',
'chevron-right': 'M6 3.5l4.5 4.5L6 12.5',
'chevron-left': 'M10 3.5L5.5 8l4.5 4.5',
search: 'M7 12.5a5.5 5.5 0 1 0 0-11 5.5 5.5 0 0 0 0 11zM11 11l3.5 3.5',
menu: 'M2.5 4.5h11M2.5 8h11M2.5 11.5h11',
copy: 'M5.5 5.5h8v8h-8zM10.5 3.5V3A1.5 1.5 0 0 0 9 1.5H3A1.5 1.5 0 0 0 1.5 3v6A1.5 1.5 0 0 0 3 10.5h.5',
play: 'M5 3.5v9l7-4.5z',
'map-pin': 'M8 14.5s4.5-4.2 4.5-8a4.5 4.5 0 0 0-9 0c0 3.8 4.5 8 4.5 8zM8 8a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3z',
calendar: 'M2.5 4h11v9.5h-11zM2.5 7h11M5.5 2.5v3M10.5 2.5v3',
settings: 'M8 10a2 2 0 1 0 0-4 2 2 0 0 0 0 4zM8 1.5v2M8 12.5v2M1.5 8h2M12.5 8h2M3.4 3.4l1.4 1.4M11.2 11.2l1.4 1.4M3.4 12.6l1.4-1.4M11.2 4.8l1.4-1.4',
user: 'M8 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM2.5 14.5a5.5 5.5 0 0 1 11 0',
mail: 'M2 3.5h12v9H2zM2.5 4l5.5 4.5L13.5 4',
bell: 'M4 11V7a4 4 0 0 1 8 0v4l1.5 1.5h-11zM6.5 14h3',
trash: 'M2.5 4h11M6 4V2.5h4V4M4 4l.7 9.5h6.6L12 4',
edit: 'M10.5 2.5l3 3-8 8h-3v-3z',
download: 'M8 2.5v8M4.5 7L8 10.5 11.5 7M2.5 13.5h11',
info: 'M8 14.5a6.5 6.5 0 1 0 0-13 6.5 6.5 0 0 0 0 13zM8 7.5V11M8 5h.01',
alert: 'M8 2l6.5 11.5h-13zM8 6.5v3M8 11.5h.01',
} as const;
export type IconName = keyof typeof ICONS;
export const iconClasses = 'inline-block size-4 shrink-0';---
import { cn } from '@/lib/utils';
import { ICONS, iconClasses, type IconName } from './icon.variants';
interface Props {
name: IconName;
/** Only when the icon means something on its own; otherwise it is hidden from screen readers. */
label?: string;
class?: string;
}
const { name, label, class: className } = Astro.props;
---
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" role={label ? 'img' : undefined} aria-label={label} aria-hidden={label ? undefined : 'true'} class={cn(iconClasses, className)}><path d={ICONS[name]} /></svg>/** Caseroom's icons: drawn on a 16px grid with a 1.5px stroke, round caps and joins, so they sit with the text.
* Decorative by default (aria-hidden); give a label when the icon is the only content of a control or carries
* meaning. Sizes follow the text: 16px with text-sm, 20px for larger controls. */
export const ICONS = {
'arrow-right': 'M3 8h10M9 4l4 4-4 4',
'arrow-up-right': 'M5 11l6-6M6 5h5v5',
check: 'M3.5 8.5l3 3 6-7',
x: 'M4 4l8 8M12 4l-8 8',
plus: 'M8 3v10M3 8h10',
minus: 'M3.5 8h9',
'chevron-down': 'M4 6l4 4 4-4',
'chevron-right': 'M6 3.5l4.5 4.5L6 12.5',
'chevron-left': 'M10 3.5L5.5 8l4.5 4.5',
search: 'M7 12.5a5.5 5.5 0 1 0 0-11 5.5 5.5 0 0 0 0 11zM11 11l3.5 3.5',
menu: 'M2.5 4.5h11M2.5 8h11M2.5 11.5h11',
copy: 'M5.5 5.5h8v8h-8zM10.5 3.5V3A1.5 1.5 0 0 0 9 1.5H3A1.5 1.5 0 0 0 1.5 3v6A1.5 1.5 0 0 0 3 10.5h.5',
play: 'M5 3.5v9l7-4.5z',
'map-pin': 'M8 14.5s4.5-4.2 4.5-8a4.5 4.5 0 0 0-9 0c0 3.8 4.5 8 4.5 8zM8 8a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3z',
calendar: 'M2.5 4h11v9.5h-11zM2.5 7h11M5.5 2.5v3M10.5 2.5v3',
settings: 'M8 10a2 2 0 1 0 0-4 2 2 0 0 0 0 4zM8 1.5v2M8 12.5v2M1.5 8h2M12.5 8h2M3.4 3.4l1.4 1.4M11.2 11.2l1.4 1.4M3.4 12.6l1.4-1.4M11.2 4.8l1.4-1.4',
user: 'M8 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM2.5 14.5a5.5 5.5 0 0 1 11 0',
mail: 'M2 3.5h12v9H2zM2.5 4l5.5 4.5L13.5 4',
bell: 'M4 11V7a4 4 0 0 1 8 0v4l1.5 1.5h-11zM6.5 14h3',
trash: 'M2.5 4h11M6 4V2.5h4V4M4 4l.7 9.5h6.6L12 4',
edit: 'M10.5 2.5l3 3-8 8h-3v-3z',
download: 'M8 2.5v8M4.5 7L8 10.5 11.5 7M2.5 13.5h11',
info: 'M8 14.5a6.5 6.5 0 1 0 0-13 6.5 6.5 0 0 0 0 13zM8 7.5V11M8 5h.01',
alert: 'M8 2l6.5 11.5h-13zM8 6.5v3M8 11.5h.01',
} as const;
export type IconName = keyof typeof ICONS;
export const iconClasses = 'inline-block size-4 shrink-0';<ul class="grid w-full max-w-2xl grid-cols-3 gap-2 sm:grid-cols-4 md:grid-cols-6" aria-label="Icons">
<li class="flex flex-col items-center gap-2 rounded-lg bg-muted/60 px-2 py-4 text-center">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="inline-block shrink-0 size-5"><path d="M3 8h10M9 4l4 4-4 4"></path></svg>
<span class="font-mono text-[11px] text-muted-foreground">arrow-right</span>
</li>
<li class="flex flex-col items-center gap-2 rounded-lg bg-muted/60 px-2 py-4 text-center">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="inline-block shrink-0 size-5"><path d="M5 11l6-6M6 5h5v5"></path></svg>
<span class="font-mono text-[11px] text-muted-foreground">arrow-up-right</span>
</li>
<li class="flex flex-col items-center gap-2 rounded-lg bg-muted/60 px-2 py-4 text-center">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="inline-block shrink-0 size-5"><path d="M3.5 8.5l3 3 6-7"></path></svg>
<span class="font-mono text-[11px] text-muted-foreground">check</span>
</li>
<li class="flex flex-col items-center gap-2 rounded-lg bg-muted/60 px-2 py-4 text-center">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="inline-block shrink-0 size-5"><path d="M4 4l8 8M12 4l-8 8"></path></svg>
<span class="font-mono text-[11px] text-muted-foreground">x</span>
</li>
<li class="flex flex-col items-center gap-2 rounded-lg bg-muted/60 px-2 py-4 text-center">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="inline-block shrink-0 size-5"><path d="M8 3v10M3 8h10"></path></svg>
<span class="font-mono text-[11px] text-muted-foreground">plus</span>
</li>
<li class="flex flex-col items-center gap-2 rounded-lg bg-muted/60 px-2 py-4 text-center">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="inline-block shrink-0 size-5"><path d="M3.5 8h9"></path></svg>
<span class="font-mono text-[11px] text-muted-foreground">minus</span>
</li>
<li class="flex flex-col items-center gap-2 rounded-lg bg-muted/60 px-2 py-4 text-center">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="inline-block shrink-0 size-5"><path d="M4 6l4 4 4-4"></path></svg>
<span class="font-mono text-[11px] text-muted-foreground">chevron-down</span>
</li>
<li class="flex flex-col items-center gap-2 rounded-lg bg-muted/60 px-2 py-4 text-center">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="inline-block shrink-0 size-5"><path d="M6 3.5l4.5 4.5L6 12.5"></path></svg>
<span class="font-mono text-[11px] text-muted-foreground">chevron-right</span>
</li>
<li class="flex flex-col items-center gap-2 rounded-lg bg-muted/60 px-2 py-4 text-center">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="inline-block shrink-0 size-5"><path d="M10 3.5L5.5 8l4.5 4.5"></path></svg>
<span class="font-mono text-[11px] text-muted-foreground">chevron-left</span>
</li>
<li class="flex flex-col items-center gap-2 rounded-lg bg-muted/60 px-2 py-4 text-center">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="inline-block shrink-0 size-5"><path d="M7 12.5a5.5 5.5 0 1 0 0-11 5.5 5.5 0 0 0 0 11zM11 11l3.5 3.5"></path></svg>
<span class="font-mono text-[11px] text-muted-foreground">search</span>
</li>
<li class="flex flex-col items-center gap-2 rounded-lg bg-muted/60 px-2 py-4 text-center">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="inline-block shrink-0 size-5"><path d="M2.5 4.5h11M2.5 8h11M2.5 11.5h11"></path></svg>
<span class="font-mono text-[11px] text-muted-foreground">menu</span>
</li>
<li class="flex flex-col items-center gap-2 rounded-lg bg-muted/60 px-2 py-4 text-center">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="inline-block shrink-0 size-5"><path d="M5.5 5.5h8v8h-8zM10.5 3.5V3A1.5 1.5 0 0 0 9 1.5H3A1.5 1.5 0 0 0 1.5 3v6A1.5 1.5 0 0 0 3 10.5h.5"></path></svg>
<span class="font-mono text-[11px] text-muted-foreground">copy</span>
</li>
<li class="flex flex-col items-center gap-2 rounded-lg bg-muted/60 px-2 py-4 text-center">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="inline-block shrink-0 size-5"><path d="M5 3.5v9l7-4.5z"></path></svg>
<span class="font-mono text-[11px] text-muted-foreground">play</span>
</li>
<li class="flex flex-col items-center gap-2 rounded-lg bg-muted/60 px-2 py-4 text-center">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="inline-block shrink-0 size-5"><path d="M8 14.5s4.5-4.2 4.5-8a4.5 4.5 0 0 0-9 0c0 3.8 4.5 8 4.5 8zM8 8a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3z"></path></svg>
<span class="font-mono text-[11px] text-muted-foreground">map-pin</span>
</li>
<li class="flex flex-col items-center gap-2 rounded-lg bg-muted/60 px-2 py-4 text-center">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="inline-block shrink-0 size-5"><path d="M2.5 4h11v9.5h-11zM2.5 7h11M5.5 2.5v3M10.5 2.5v3"></path></svg>
<span class="font-mono text-[11px] text-muted-foreground">calendar</span>
</li>
<li class="flex flex-col items-center gap-2 rounded-lg bg-muted/60 px-2 py-4 text-center">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="inline-block shrink-0 size-5"><path d="M8 10a2 2 0 1 0 0-4 2 2 0 0 0 0 4zM8 1.5v2M8 12.5v2M1.5 8h2M12.5 8h2M3.4 3.4l1.4 1.4M11.2 11.2l1.4 1.4M3.4 12.6l1.4-1.4M11.2 4.8l1.4-1.4"></path></svg>
<span class="font-mono text-[11px] text-muted-foreground">settings</span>
</li>
<li class="flex flex-col items-center gap-2 rounded-lg bg-muted/60 px-2 py-4 text-center">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="inline-block shrink-0 size-5"><path d="M8 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM2.5 14.5a5.5 5.5 0 0 1 11 0"></path></svg>
<span class="font-mono text-[11px] text-muted-foreground">user</span>
</li>
<li class="flex flex-col items-center gap-2 rounded-lg bg-muted/60 px-2 py-4 text-center">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="inline-block shrink-0 size-5"><path d="M2 3.5h12v9H2zM2.5 4l5.5 4.5L13.5 4"></path></svg>
<span class="font-mono text-[11px] text-muted-foreground">mail</span>
</li>
<li class="flex flex-col items-center gap-2 rounded-lg bg-muted/60 px-2 py-4 text-center">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="inline-block shrink-0 size-5"><path d="M4 11V7a4 4 0 0 1 8 0v4l1.5 1.5h-11zM6.5 14h3"></path></svg>
<span class="font-mono text-[11px] text-muted-foreground">bell</span>
</li>
<li class="flex flex-col items-center gap-2 rounded-lg bg-muted/60 px-2 py-4 text-center">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="inline-block shrink-0 size-5"><path d="M2.5 4h11M6 4V2.5h4V4M4 4l.7 9.5h6.6L12 4"></path></svg>
<span class="font-mono text-[11px] text-muted-foreground">trash</span>
</li>
<li class="flex flex-col items-center gap-2 rounded-lg bg-muted/60 px-2 py-4 text-center">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="inline-block shrink-0 size-5"><path d="M10.5 2.5l3 3-8 8h-3v-3z"></path></svg>
<span class="font-mono text-[11px] text-muted-foreground">edit</span>
</li>
<li class="flex flex-col items-center gap-2 rounded-lg bg-muted/60 px-2 py-4 text-center">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="inline-block shrink-0 size-5"><path d="M8 2.5v8M4.5 7L8 10.5 11.5 7M2.5 13.5h11"></path></svg>
<span class="font-mono text-[11px] text-muted-foreground">download</span>
</li>
<li class="flex flex-col items-center gap-2 rounded-lg bg-muted/60 px-2 py-4 text-center">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="inline-block shrink-0 size-5"><path d="M8 14.5a6.5 6.5 0 1 0 0-13 6.5 6.5 0 0 0 0 13zM8 7.5V11M8 5h.01"></path></svg>
<span class="font-mono text-[11px] text-muted-foreground">info</span>
</li>
<li class="flex flex-col items-center gap-2 rounded-lg bg-muted/60 px-2 py-4 text-center">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="inline-block shrink-0 size-5"><path d="M8 2l6.5 11.5h-13zM8 6.5v3M8 11.5h.01"></path></svg>
<span class="font-mono text-[11px] text-muted-foreground">alert</span>
</li>
</ul>