Use icons in an app built with @allxsmith/bestax-bulma — the Icon/IconText components and the five supported libraries (Font Awesome, Material Design Icons, Ionicons, Google Material Icons, Material Symbols). Use when adding an icon, choosing or configuring the app-wide icon library, fixing an icon that renders blank, pairing icons with text, or making icons accessible (decorative vs labeled).
78
98%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Low
Low-risk findings worth noting
Icon renders a Bulma icon container (span.icon) around a glyph from any of five icon
libraries behind one normalized API. IconText pairs icons with text. The library ships no
icon fonts — the chosen library's package (or CDN script) must be installed in the app.
import { ConfigProvider, Icon, IconText } from '@allxsmith/bestax-bulma';
// Set the library ONCE at the app root; <Icon> then never needs `library`.
<ConfigProvider iconLibrary="fa">
<App />
</ConfigProvider>;
// Inside the app:
<Icon name="rocket" ariaLabel="Launch" />;
<IconText iconProps={{ name: 'star', 'aria-hidden': 'true' }}>
Starred
</IconText>;| Library | iconLibrary / library value | Name format | Example name |
|---|---|---|---|
| Font Awesome (default) | 'fa' | kebab-case, no fa- prefix | rocket |
| Material Design Icons | 'mdi' | kebab-case, no mdi- prefix | rocket-launch |
| Ionicons | 'ion' | kebab-case | rocket |
| Google Material Icons | 'material-icons' | snake_case (a text ligature) | rocket_launch |
| Material Symbols | 'material-symbols' | snake_case (a text ligature) | rocket_launch |
⚠️ The Ionicons value is 'ion', not 'ionicons'. The npm create bestax scaffold's
--icon ionicons flag maps to iconLibrary="ion" — passing 'ionicons' to ConfigProvider
or library silently renders nothing.
The same glyph has a different name per library (rocket vs rocket-launch vs
rocket_launch). When an icon renders blank, the name format for the active library is the
first thing to check. A redundant fa-/mdi- prefix in name is tolerated (stripped), but
don't rely on it.
size — 'small' | 'medium' | 'large' sizes the Bulma container (is-small ≈ 1rem,
is-medium ≈ 2rem, is-large ≈ 3rem box). To scale the glyph, use features
(Font Awesome 'fa-lg'/'fa-2x') or a Bulma text-size class ('is-size-3').variant — per-library style: Font Awesome solid (default) / regular / brands /
light / duotone / thin; Material Icons filled (default) / outlined / round /
sharp; Material Symbols outlined (default) / rounded / sharp; Ionicons outline /
sharp. MDI has no variants. Note Material Icons uses round, Material Symbols
uses rounded.features — extra library classes, string or array: 'fa-spin', ['fa-lg', 'fa-border'].textColor="primary", textColor="danger", etc.Icon also accepts children instead of name — an inline SVG, a react-icons component, a
Font Awesome React <FontAwesomeIcon>, … — rendered in place of a class-based glyph. name
and children are mutually exclusive (the type rejects passing both, or neither). size,
textColor, bgColor, ariaLabel and containerClassName behave identically; library,
variant, features and libraryFeatures are ignored since there's no class-based glyph to
style.
<Icon ariaLabel="Custom icon">
<MyReactIconsComponent />
</Icon>IconText's iconProps / items[].iconProps and Control's iconLeft/iconRight accept
the same escape hatch — pass a node directly (instead of an IconProps object) and it is
wrapped in an Icon for you: <IconText iconProps={<MySvg />}>Starred</IconText>.
Panel.Icon takes the same children, but its container is panel-icon rather than icon —
it always overrides containerClassName, so style and query that class instead.
⚠️ children excludes undefined. Write a conditional icon as cond ? <MySvg /> : null
(or cond && <MySvg />), never cond ? <MySvg /> : undefined — the latter is a type error,
because the renderer would fall through to the name path with no name. In the IconText and
Control slots a falsy node counts as "no icon": nothing is rendered, and Control falls back
to iconLeftName/iconRightName if one is given, otherwise leaving the icon column unreserved.
An Icon is decorative unless it is named: with no ariaLabel it renders aria-hidden="true"
and no name. Name it with its camelCase ariaLabel prop, and it renders role="img" with that
aria-label. Only a few components declare that prop (Icon, Delete, Slider, Carousel):
everything else takes the standard aria-label attribute, e.g.
<Navbar.Burger aria-label="menu" />.
ariaLabel="Delete item".IconText
or a labeled Button): leave ariaLabel off, and the icon stays out of the accessible
name. An explicit aria-hidden="true", as in the examples here, says the same thing.<Button aria-label="Delete item">), not the icon.references/icon-libraries.md — per-library setup (install/import/CDN), the full
name-format and variant tables, features values, and the blank-icon troubleshooting list.examples/icon-usage.tsx — runnable example: ConfigProvider setup, sizes, variants,
colors, IconText, and decorative-vs-labeled patterns.ef9f79b
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.