Icons

Icons give actions and objects a familiar shape, so people can scan a screen quickly. Nuton uses Remix Icon, coloured with the Icon tokens and always paired with a text name.

  • Beta
  • Accessibility
  • Figma Mapped collection, Icon/*
  • packages/tokens/src/figma/snapshot.json

Beta. Icon colours are Figma variables (Mapped/Icon/*), light mode only until dark values are designed (TD-11). There are no icon-size tokens: components size icons with interim spacing tokens (pending a Figma home, D9) or Figma type line heights, and the 56px key icon uses a raw 28px glyph. Stable needs icon-size tokens in Figma and the design review of the Lucide-to-Remix migration (D1).

Overview

Remix Icon (@remixicon/react 4.9.0) is Nuton's only icon set (D1). Icons are drawn on a 24px grid, take their colour from currentColor and come in two styles: Line and Fill.

16px · Field hint
20px · Buttons, menus, small inputs
24px · Large input
32px · Key icon 64
RiBookOpenLine · Line
RiBookOpenFill · Fill
RiSettings3Line · Line
RiSettings3Fill · Fill
  • Line is the default. Buttons, inputs and menus in @nuton/ui use Line icons.
  • Fill is for small status marks, where a solid shape reads better at a small size: the Field hint uses RiInformationFill and Avatar status badges use RiPushpinFill, RiStarFill and RiVerifiedBadgeFill. Guidance on Fill for selected or active states is still to be agreed with design.
  • Icons are never bundled in @nuton/ui. Apps import the icons they need and pass them in through props such as leadingIcon or icon.

Common icons in Nuton

The icons @nuton/ui uses plus the verified Remix candidates from the Lucide inventory. Every name below is an export of @remixicon/react 4.9.0. For anything else, search the full set and check the export exists before you use it.

Filter by name or use, for example “lesson” or “delete”.

50 of 50 icons

  • RiSparkling2LineAI actions: generate, summarise
  • RiMagicLineAI rewrite, improve
  • RiAddLineCreate a lesson or space
  • RiBookOpenLineLessons, reading
  • RiGraduationCapLineCourses, learners
  • RiFileTextLineDocuments, notes
  • RiPresentationLineSlides
  • RiFolderLineSpaces, collections
  • RiFolderOpenLineOpen space
  • RiGroupLineClass, members
  • RiUser6LineProfile, account
  • RiHomeLineHome
  • RiSearchLineSearch, Combobox
  • RiSettings3LineSettings
  • RiEditLineEdit
  • RiPencilLineRename, write
  • RiDeleteBinLineDelete
  • RiShareLineShare
  • RiDownload2LineDownload
  • RiUpload2LineUpload material
  • RiFileCopyLineCopy
  • RiSendPlaneLineSend a message
  • RiMailLineEmail, invite
  • RiMegaphoneLineAnnouncements
  • RiCalendarLineDue dates
  • RiTimerLineTimed quiz
  • RiBarChartBoxLineProgress, analytics
  • RiLayoutGridLineGrid view
  • RiImageLineImages
  • RiVideoLineVideo lessons
  • RiMicLineVoice input
  • RiPlayLineStart, play
  • RiLightbulbLineTips, ideas
  • RiPushpinLinePin; Avatar status
  • RiLockLinePrivate, locked
  • RiEyeLineShow password
  • RiEyeOffLineHide password
  • RiInformationLineField hint (fill)
  • RiErrorWarningLineError
  • RiAlertLineWarning
  • RiCheckboxCircleLineDone, success
  • RiCheckLineSelected item in a menu
  • RiCloseLineClose, remove
  • RiMore2LineMore actions
  • RiRefreshLineRegenerate, retry
  • RiLoader4LineLoading
  • RiArrowLeftLineBack
  • RiArrowRightLineContinue
  • RiArrowDownSLineSelect chevron
  • RiArrowUpSLineCollapse

Licence

Remix Icon License v1.0: conditions

Remix Icon may be used inside Nuton's products and its design system. The licence forbids a standalone icon pack, so Nuton doesn't publish or re-export the icons as a set: there is no @nuton/icons package (D1, provenance review). Add @remixicon/react as a dependency of your app and import individual icons. Don't copy the SVGs into a shared library, and don't redistribute them on their own.

Migrating from Lucide

Migration in progress (D1)

The teacher app still uses Lucide: 68 distinct icons in 181 places. Each has a Remix candidate that exists in the package, and 23 have more than one plausible match (for example Sparkles → RiSparkling2Line or RiSparklingLine). Every row needs design review; nothing has been swapped yet. Migrate with a semantic and visual check, never by search and replace, and don't mix Lucide and Remix on one screen. The list is in docs/migration/icon-inventory-teacher.md.

Tokens

Generated from @nuton/tokens. Icon colours come from the Figma Mapped collection. Icon sizes have no tokens of their own; components use spacing tokens and type line heights.

Icon colours

Icon colour tokens
PreviewTokenValueSource
--nu-icon-strong-950→ gray-950#171717FigmaMapped/Icon/Strong-950
--nu-icon-sub-600→ gray-600#5c5c5cFigmaMapped/Icon/Sub-600
--nu-icon-soft-400→ gray-400#a4a4a4FigmaMapped/Icon/Soft-400
--nu-icon-disabled-300→ gray-300#d1d1d1FigmaMapped/Icon/Disabled-300
--nu-icon-white→ gray-0#ffffffFigmaMapped/Icon/White

Sizes used for icons

Spacing and line-height tokens used to size icons
PreviewTokenValueSource
--nu-space-312pxInterim
--nu-space-416pxInterim
--nu-space-520pxInterim
--nu-space-624pxInterim
--nu-space-832pxInterim
--nu-type-label-small-line-height20pxFigmaTextStyle/Label/Small
--nu-type-paragraph-x-small-line-height16pxFigmaTextStyle/Paragraph/X Small

Spacing tokens are interim: Figma doesn't bind spacing yet (D9). Button, Link button and Button group size their icons with the Label/Small or Paragraph/X Small line height, so the icon matches the text line.

Icon sizes in components

SlotSize tokenSizeColour
Field hint and error icon--nu-space-416pxIcon/Soft-400 (error: State/Error/Base; disabled: Icon/Disabled-300)
Button, Link button (md), Button group (sm, xs)--nu-type-label-small-line-height20pxInherits the label colour (currentColor)
Link button (sm), Button group (2xs)--nu-type-paragraph-x-small-line-height16pxInherits the label colour (currentColor)
Input leading icon, large (48)--nu-space-624pxIcon/Sub-600; Icon/Soft-400 while empty; Icon/Strong-950 when invalid
Input leading icon, small (36) and inline; trailing icon--nu-space-520pxSame as above; disabled: Icon/Disabled-300
Menu item leading and trailing icon, check mark--nu-space-520pxIcon/Sub-600; check mark Icon/Strong-950
Combobox and command menu search icon--nu-space-520pxIcon/Sub-600 in the command menu
Checkbox indicator tick--nu-space-312pxText/White on State/Primary/Base
Key icon glyph at 32 and 40--nu-space-520pxState/<colour>/Base (gray: Icon/Sub-600)
Key icon glyph at 48--nu-space-624pxAs above
Key icon glyph at 64--nu-space-832pxAs above
Key icon glyph at 56None (raw value in KeyIcon.css)28pxAs above

Read from the component CSS in packages/ui. The 56px key icon is the only icon size without a token; it needs one when icon sizes get a Figma home.

Usage

tsx
import { RiAddLine } from '@remixicon/react'
import { Button } from '@nuton/ui'

// Pass the icon to the component. It sizes, colours and hides the icon for you.
<Button leadingIcon={<RiAddLine />}>New lesson</Button>

CSS variables

css
.lesson-meta__icon {
  inline-size: var(--nu-space-5);
  block-size: var(--nu-space-5);
  color: var(--nu-icon-sub-600); /* Remix icons fill with currentColor */
}

Tailwind

Both Tailwind outputs expose the icon colours as colour utilities. Sizes aren't exposed as utilities; use the CSS variables.

tsx
/* app.css */
@import "tailwindcss";
@import "@nuton/tokens/tokens.css";
@import "@nuton/tokens/tailwind-v4-theme.css";

<RiTimerLine className="text-icon-sub-600" aria-hidden="true" />

Choosing a token

  • --nu-icon-strong-950: icons that carry meaning on their own, and icons next to strong text.
  • --nu-icon-sub-600: the default for icons next to secondary text, in inputs and in menus.
  • --nu-icon-soft-400: decorative icons only, such as an empty input's search icon or a hint icon whose text carries the message. Below 3:1 on white, so never the only cue.
  • --nu-icon-disabled-300: icons inside disabled controls.
  • --nu-icon-white: icons on dark or saturated fills, such as a filled button.
  • Inside a component, let the icon inherit currentColor. Set an icon token only for standalone icons.

In use

Real @nuton/ui components. Each sizes and colours its icon from tokens, and hides it from assistive technology because the text names the control.

Buttons

Fields and inputs

Search by title or topic.

Shown to everyone in the space.

Key icons

Icon-only actions

Accessibility

Decorative or meaningful

An icon next to text is decorative: hide it with aria-hidden="true" so the name isn't read twice. @nuton/ui does this for every icon prop. An icon that stands alone and carries meaning needs a name: role="img" with an aria-label, or KeyIcon's label.

Icon-only buttons

An icon-only Button or ButtonGroupItem must have an aria-label (or aria-labelledby) that names the action, such as “Share lesson”. Both warn in development when it's missing. Use icon-only only for familiar actions; otherwise show the label.

Contrast (WCAG 1.4.11)

A meaningful icon needs 3:1 against its background. Icon/Strong-950 and Icon/Sub-600 resolve to the same greys as Text/Strong-950 (17.93:1 on white) and Text/Sub-600 (6.69:1 on white, 6.24:1 on Weak-50). Icon/Soft-400 shares Text/Soft-400's grey, 2.49:1 on white (C1), so it's for decorative icons only (C12). Icon/Disabled-300 shares Stroke/Sub-300's grey, 1.53:1 (C7); disabled controls are exempt.

Target size

The smallest icon-only button is 36 × 36, above the 24 × 24 minimum (WCAG 2.5.8). Two known gaps: icon-only Button group items at 2xs sit edge to edge (C26), and Link button has no padding or icon-only mode (C28).

Not by icon alone

Don't rely on an icon's shape or colour to carry a state. An error shows its message, and a selected menu item has a check mark as well as its fill (C18).

Forced colours

Remix icons fill with currentColor, so they follow the system colours in Windows high-contrast mode.

You must: hide decorative icons; name icon-only buttons and meaningful standalone icons; use Icon/Sub-600 or stronger for icons that carry meaning.

Guidelines and related

Use icons to

  • Help people scan: a leading icon on a button, menu item or search field.
  • Label a familiar action in a tight space, such as edit, share or more actions.
  • Mark status next to text, such as a hint, an error or a pinned item.

Don't use icons to

  • Replace a label for an uncommon or destructive action.
  • Decorate every item in a list; when everything has an icon, none of them help.
  • Mix icon families. Remix only (D1), no Lucide or custom SVGs alongside it.

Do and don't

DoName icon-only buttons after the action. “Share lesson” is what a screen reader announces; the icon alone says nothing.
Don'tDon't hide a destructive action behind an icon. A bin with no label is easy to mistake. Show the words.
DoKeep one style across a group. Line icons side by side read as a set.
Don'tDon't mix Line and Fill in one group. The filled icon looks selected when it isn't.
DoUse Sub-600 or stronger for an icon that means something. It stays visible against white and Weak-50.
Don'tDon't use Soft-400 for a meaningful icon. At 2.49:1 it fails the 3:1 non-text minimum (C1).