Documentation

Icons

VitNode's icon system - lucide-react icons, a size scale, auto-sized icons in buttons and badges, icons loaded by name, brand logos and accessible icon-only buttons.

VitNode uses lucide-react for icons: over 1,500 outlined icons with one stroke style. Components size them for you, so most of the time you just drop one in.

Size scale

  • size-312pxBadges, xs buttons
  • size-3.514pxInline with text-xs
  • size-416pxDefault: buttons, menus, inputs
  • size-520pxNavigation, list rows
  • size-624pxEmpty states, feature tiles

size-4 is the default. It matches text-sm, the size of buttons, menus and inputs. Go up for navigation and empty states, down for badges.

Icons in components

leading
trailing
icon only
badge
Verified
input

Buttons, badges and input groups size any child svg that has no size-* class. Add data-icon="inline-start" or "inline-end" so the button trims its padding on that side.

<Button>
  <PlusIcon data-icon="inline-start" />
  New post
</Button>

Stroke

strokeWidth={1.5}
12 replies
strokeWidth={2} default
12 replies
strokeWidth={2.5}
12 replies

Keep the default strokeWidth={2}. It sits right next to font-medium text. Thinner or bolder strokes are for big hero icons, not your toolbar.

Icons by name

name="rocket"

Store an icon as a string and render it with DynamicIcon. Each icon loads on its own, and icons rendered on the server arrive with the page, so nothing pops in. An unknown name renders nothing.

import { DynamicIcon } from '@vitnode/core/components/ui/dynamic-icon'

<DynamicIcon className="size-5" name="shield-check" />

Letting users pick one? The Emoji & Icon Picker returns exactly this name.

Do and don't

Do
Give icon-only buttons an aria-label, like "Delete post".
Don't
Ship a bare icon and hope everyone reads trash cans.
Do
Use the real brand mark as an SVG.
Don't
Fake a logo with a lookalike lucide icon.
Do
Keep one size and stroke in a row.
Don't
Mix sizes and strokes side by side.
  • Lucide hides icons from screen readers by default (aria-hidden="true"), so an icon next to text needs nothing extra.
  • Icon-only buttons need an aria-label. TypeScript asks for it on size="icon".
  • Lucide has no brand logos. Use an inline SVG with fill="currentColor" and aria-hidden.