Import#
import { Icon } from '@dnb/eufemia'
Description#
The main Icon component is a wrapper for whatever icon you place within it. This means a span wrapping an inline SVG.
You can use any content you like inside this Icon component.
Relevant links#
Why use it?#
You will get several advantages when using it, such as:
- Responsiveness in terms of
font-size - Coloring
- Accessibility
Importing Icons#
In case your environment does not support tree-shaking, import the icons explicitly.
// Named ES importimport { bell } from '@dnb/eufemia/icons'// or named import with modifierimport { bell as Bell } from '@dnb/eufemia/icons'// Default and explicit ES importimport Bell from '@dnb/eufemia/icons/bell'
Icon Sizes#
Exists in the Icon Library
- default
1rem(16px) - medium
1.5rem(24px)
Additional Sizes
- small
0.75rem(12px) - large
2rem(32px) - x-large
2.5rem(40px) - xx-large
3rem(48px) - custom-size will not be responsive. Width and Height is set as
pixels
Filled Icons#
Some icons support a filled variant where the SVG paths are filled with currentColor instead of being stroked outlines. This is useful for visual emphasis — for example, a filled star to indicate a favorited item, or a filled chevron inside a button.
Using the fill prop#
Set fill on an Icon to fill its SVG paths with currentColor:
<Icon icon={star} fill />
See the Icon Library for icons that are known to look good when filled.
Animated Icons#
Animated icons are an opt-in enhancement. Use them to reinforce nearby feedback, such as a bell moving once when a new notification arrives. Motion must not be the only indication that something changed.
Read the Animation Principles for where, why, and when to use motion, and Motion for visual examples and implementation guidance.
See the animated icon demos for one-time, replayed, and looping examples.
Animated icons can be used in buttons when the trigger matches the purpose:
- Animate once on hover to invite or preview an action.
- Animate after a click only to acknowledge the interaction itself.
- Animate after a state change to confirm the actual outcome, such as showing an animated check after saving succeeds.
- Loop only while the icon represents genuine ongoing activity.
Animated icons intentionally support direct default imports only. They are not available as named imports from @dnb/eufemia/icons. The direct import is the bundle boundary that keeps each icon's animation styles out of applications that do not use it. The icon remains static unless animate is enabled.
import bell from '@dnb/eufemia/icons/animated/bell'import arrowRight from '@dnb/eufemia/icons/animated/arrow_right'<Icon icon={bell} /><Icon icon={bell} animate />
Do not import animated icons from a shared barrel:
// Not supportedimport { bell } from '@dnb/eufemia/icons/animated'
Import bell_medium when the icon is displayed at medium size or larger.
Use animate="loop" only for genuine ongoing activity, and stop the loop when the activity ends. Change animationKey to replay a one-time animation after a new event.
<Icon icon={bell} animate animationKey={notificationId} /><Icon icon={bell} animate={isActive ? 'loop' : false} /><Icon icon={arrowRight} animateWhen="hover" />
The animation is disabled automatically when the user prefers reduced motion.
Use animateWhen="hover" to animate an icon when the icon itself, or an interactive parent such as a button or link, is hovered.
Custom project Icons#
For decorative or functional icons (not illustrations), use SVG as it gives the user responsiveness and better accessibility. It also gives you more control, so you can change the color and size inherited by the parent HTML element.
To optimize your SVG icons to be used with Eufemia, you can follow these steps or at least get inspired:
- Make sure your SVG icon fits in the two sizes (default of
16pxand medium of24px) with the correct stroke thickness of1.5px. - Copy the SVG markup (in Figma,
right click->Copy as->Copy as SVG). - Declutter and remove ID attributes in the markup, so they do not appear twice in your web application DOM. In most cases, you do not need
<defs ... />and the corresponding ids anyway. - Optimize the SVG. Use e.g. Online SVGOMG by using
Paste markup. - NB: Do not remove
viewBox! TheviewBoxwill together with some CSS ensure that the icon scales based on the root font-size. - Copy again the optimized markup and paste it into your JSX component (inline) or SVG file.
- Consume the custom icons with either dynamic imports (
import(...)) if you have many icons, or use static imports, like so:
If you have an SVG loader#
import ImportedSVGIcon from 'my-icons/custom_icon.svg'render(<Icon icon={ImportedSVGIcon} />)
Inline the SVG in your JSX#
function CustomSVGIcon(props) {return <svg {...props}>...</svg>}render(<Button icon={CustomSVGIcon} />)
SVG import in Create React App#
import { ReactComponent as CustomIcon } from './custom_icon.svg'render(<Icon size="medium">{CustomIcon}</Icon>)
Primary Icon#
There is also the IconPrimary component, which comes with all the Primary Icons included in @dnb/eufemia. You do not have to import the primary icons separately.
Related components#
Icon is part of the Content category. Other components for similar needs:
- Accordion — to let people open and close sections of related content.
- Avatar — to make a person, company, or profile easier to recognize.
- Card — to group related content in a clear, separated area.
- CountryFlag — to show a country by its flag from an ISO country code.
- DateFormat — to show dates in the correct DNB format.
- Heading — to create accessible page headings with the correct level.
Demos#
Default and Medium-sized icons (Responsive)#
<Icon icon={Bell} title="Give Icons a Title, or ..." /> <Icon icon={BellMedium} aria-hidden /> <Bell title="I'm not responsive!" /> {/* <- Not responsive! */}
Icons with border#
NB: Use it with caution. It should not be used where it can confuse users with being a clickable button.
<Flex.Horizontal align="center"> <Icon border={true} icon={Bell} /> <Icon border={true} icon={BellMedium} size="medium" /> <IconPrimary border={true} icon="information" /> <IconPrimary border={true} icon="information" size="medium" /> <Button icon={<IconPrimary icon="add" border />} text="Button" /> </Flex.Horizontal>
Filled icons#
Use the fill prop on a single icon to fill it.
<Flex.Stack> <Flex.Horizontal align="center"> <Icon icon={Star} fill /> <Icon icon={Heart} fill /> <Avatar icon={<Icon icon={Star} fill />} size="small" hasLabel /> <Button icon={<Icon icon={Heart} fill />} title="Favorite" /> </Flex.Horizontal> </Flex.Stack>
Animated icon demos#
Animated icons are static by default and only move when you opt in. Import each animated icon directly using its default export. Named imports are intentionally unavailable so each icon's animation code is only included when it is used.
Use a single animation to reinforce an event. Change animationKey to replay it while animate remains enabled.
const App = () => { const [animationKey, setAnimationKey] = useState(0) return ( <Flex.Horizontal align="center" gap="small"> <Icon icon={AnimatedBell} size="medium" animate animationKey={animationKey} aria-hidden /> <Button variant="secondary" text="Replay" onClick={() => setAnimationKey((key) => key + 1)} /> </Flex.Horizontal> ) } render(<App />)
Animated icons in buttons#
Use hover to invite or preview an action. Play the animation once and keep the button understandable without motion.
<Button variant="tertiary" text="Continue" icon={<Icon icon={AnimatedArrowRight} animateWhen="hover" />} />
Responsive to its inherited font-size#
h1 with auto sized icon
<h1 className="dnb-h--xx-large"> h1 with auto sized <Icon icon={BellMedium} size="auto" aria-hidden />{' '} icon </h1>
Icon color variations#
All of these methods will output the same color
<Icon icon={BellMedium} color="var(--color-fire-red)" title="CSS variable" /> <Icon icon={BellMedium} color="#DC2A2A" title="Hex" /> <Icon icon={BellMedium} color="rgb(220,42,42)" title="RGB" />
Icon size variations#
The official supported sizes are default and medium.
NB: If you need to use the large, x-large or xx-large sizes, then you should use the *_medium version of the icon. Ensure you import the *_medium version of the icon.
<Icon icon={BellMedium} title="Beach" size="large" /> <Icon icon={BellMedium} title="Beach" size="x-large" /> <Icon icon={BellMedium} title="Beach" size="xx-large" />
Icon transition#
Use Icon.transition() to animate between SVG icon states. Define named states and use Icon.transition.activate(element, state) to switch between them.
When icons have compatible path structures (same number and type of segments), the transition animates via CSS d property interpolation. This suits directional variants like arrow_down ↔ arrow_up or chevron_down ↔ chevron_up.
d path interpolation, so the icon transition will fall back to a simple crossfade.const directionIcon = Icon.transition({ down: arrow_down, up: arrow_up, left: arrow_left, right: arrow_right, }) const handleChange = (direction) => { const iconEl = document.querySelector( '[data-visual-test="icon-transition"] .dnb-icon' ) as HTMLElement if (iconEl) { Icon.transition.activate(iconEl, direction) } } render( <> <Flex.Horizontal align="center" gap="small"> <Icon icon={directionIcon} /> <Field.Selection variant="button" value="down" optionsLayout="horizontal" onChange={handleChange} > <Field.Option value="down" title="Down" /> <Field.Option value="up" title="Up" /> <Field.Option value="left" title="Left" /> <Field.Option value="right" title="Right" /> </Field.Selection> </Flex.Horizontal> {notSupported} </> )
Icon transition fallback#
When icons have incompatible path structures (e.g. question ↔ close), Icon.transition() automatically falls back to a transform/opacity crossfade using stacked SVGs. The same Icon.transition.activate() API works for both modes.
const helpIcon = Icon.transition({ question, close, }) const handleChange = (state) => { const iconEl = document.querySelector( '[data-visual-test="icon-transition-fallback"] .dnb-icon' ) as HTMLElement if (iconEl) { Icon.transition.activate(iconEl, state) } } render( <Flex.Horizontal align="center" gap="small"> <Icon icon={helpIcon} /> <Field.Selection variant="button" value="question" optionsLayout="horizontal" onChange={handleChange} > <Field.Option value="question" title="Question" /> <Field.Option value="close" title="Close" /> </Field.Selection> </Flex.Horizontal> )