Screen icons
StableFifteen small round-capped icons used by the library-style screens, each its own component.
The Tailwind Plus, shadcn, Magic UI and Aceternity screens follow those libraries’ softer look, so they use their own small set: round caps and joins, a 1.75 stroke (2 for the arrow, the chevrons, PanelLeft, Lock and Loader). Each icon is a component that takes any SVG attribute and is always hidden from screen readers. Swap them for your own set when you move a screen into an app.
Updated View source
The set
import type { ComponentType, SVGProps } from 'react'import { ActivityIcon, ArrowRightIcon, BellIcon, ChevronDownIcon, ChevronRightIcon, ChevronsUpDownIcon, ChevronUpIcon, FolderIcon, HomeIcon, LoaderIcon, LockIcon, MenuIcon, PanelLeftIcon, SearchIcon, SlidersIcon,} from '@rchursin/components/icons'
/**Usage
import { BellIcon, HomeIcon, SearchIcon } from '@rchursin/components/icons'<button type="button" aria-label="View notifications"> <BellIcon className="size-5" /></button>Examples
Next to the product icons
The same pictures from both sets. Keep one set per screen.
import { ArrowRightIcon, BellIcon, FolderIcon, HomeIcon, SearchIcon } from '@rchursin/components/icons'import { Icon } from '@rchursin/product/icons/Icon'
/** * The same five pictures from both sets. The screen icons (top) are softer: round caps, round * joins, a 1.75 stroke. The product set (bottom) is cut from the logo: square caps, mitred * corners, a 1.5 stroke. Keep one set per screen. */export default function ScreenIconCompare() { return ( <div className="flex w-full max-w-md flex-col gap-3"> <div className="lux-card flex flex-col divide-y divide-line rounded-2xl bg-raised"> <div className="flex flex-col gap-3 p-5"> <p className="font-mono text-[11px] tracking-[0.12em] text-fg-3 uppercase">Screen icons · round · 1.75</p> <div role="img" aria-label="Home, folder, search, bell and arrow from the screen icons" className="flex items-center gap-6 text-fg"> <HomeIcon className="size-6" /> <FolderIcon className="size-6" /> <SearchIcon className="size-6" /> <BellIcon className="size-6" /> <ArrowRightIcon className="size-6" /> </div> </div> <div className="flex flex-col gap-3 p-5"> <p className="font-mono text-[11px] tracking-[0.12em] text-fg-3 uppercase">Product icons · square · 1.5</p> <div role="img" aria-label="Home, folder, search, bell and arrow from the product icons" className="flex items-center gap-6 text-fg"> <Icon name="home" className="size-6" /> <Icon name="folder" className="size-6" /> <Icon name="search" className="size-6" /> <Icon name="bell" className="size-6" /> <Icon name="arrow-right" className="size-6" /> </div> </div> </div> </div> )}Naming the control
The icon is always hidden, so the button or the words beside it carry the name.
import { BellIcon, LoaderIcon } from '@rchursin/components/icons'
/** * The icons are always aria-hidden, so the name goes on the control: aria-label on an * icon-only button, or words beside the icon. Spin LoaderIcon with motion-safe:animate-spin, * so it stays still for people who ask for less motion. */export default function ScreenIconInButton() { return ( <div className="flex flex-wrap items-center justify-center gap-4"> <button type="button" aria-label="View notifications" className="flex size-10 items-center justify-center rounded-full text-fg-2 ring-1 ring-line ring-inset hover:bg-hover hover:text-fg focus-ring" > <BellIcon className="size-5" /> </button> <p role="status" className="flex items-center gap-2 text-[13px] text-fg-2"> <LoaderIcon className="size-4 motion-safe:animate-spin" /> Loading workspace </p> </div> )}API
Screen icons props
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | – | Size and colour, e.g. "size-5 text-fg-3". There is no size prop and the SVG sets no width or height, so always pass a size class. |
strokeWidth | number | string | 1.75 | 2 by default on ArrowRight, the chevrons, PanelLeft, Lock and Loader. Any other SVG attribute passes through to the <svg>. |
Accessibility
- Every icon renders aria-hidden="true", so it is never read. Put the name on the control (aria-label on an icon-only button) or in visible words.
- Attributes you pass come last, so aria-hidden={false} with role="img" and aria-label would name one; naming the control is more reliable.
- LoaderIcon does not spin by itself. The shadcn loading screen adds animate-spin, which keeps turning with reduced motion; use motion-safe:animate-spin in your own code.
Guidelines
Do
- Use them inside the library-style screens, where their round ends match the rest of the page.
- Size them with a size-* class and colour them with the text colour.
Don’t
- Don’t mix them with the product icons on one screen: the caps and stroke differ.
- Don’t leave an icon-only control without a name; the icon can’t provide one.
In use
Related
- IconOne component for all 161 icons: a 24-pixel grid, a 1.5 stroke, square ends, coloured by the text around it.
- Tailwind Plus screensFive screens in the Tailwind Plus style: a centred hero, a sidebar app shell, a sign-in form, a header and a loading screen.
- shadcn screensFive screens in the shadcn/ui style: a hero, an inset sidebar shell, a login card, a site header and a loading screen.
- Magic UI screensFive screens with Magic UI’s effects: retro grid, border beam, shiny and gradient text, shimmer buttons, ripples and a dock.
- Aceternity screensFive screens in the Aceternity style: a spotlight hero, a borderless sidebar, a signup-style form, a floating navbar and a lamp.
Source
The component’s own files, exactly as they run on this site.
/** * Small stroke icons used across the screens (24×24 grid, 1.75 px stroke). * They inherit size from className (e.g. size-5) and colour from the text colour. * Swap for your icon set (Heroicons, Lucide) when you move a screen into your app. */import type { SVGProps } from "react"
type IconProps = SVGProps<SVGSVGElement>
function Icon({ children, strokeWidth = 1.75, ...props }: IconProps) { return ( <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={strokeWidth} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" {...props}