Patterns
Compact Toolbar Action
When to use:
- Dense toolbars or headers need compact actions.
Composition notes:
- Keep labels explicit through
aria-label. - Reserve icon-only treatment for familiar actions.
Trade-offs:
- Saves space.
- Less explicit than text buttons.
import { Icon, IconButton, Text } from '@vega-ui/react';
import { EllipsisIcon, PencilIcon, Share2Icon } from '@vega-ui/icons';
import { useState } from 'react';
export default function BasicUsage() {
const [lastAction, setLastAction] = useState('');
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: 'var(--spacing-2)', width: '100%' }}>
<header style={{ display: 'flex', alignItems: 'center', gap: 'var(--spacing-2)' }}>
<Text size={4} fontWeight={600} style={{ flex: 1, minWidth: 0 }}>Brand guidelines</Text>
<IconButton type='button' size='sm' variant='secondary' appearance='transparent' aria-label='Rename document' onClick={() => setLastAction('Rename')}>Inline Clear Action
When to use:
- A small local control clears or removes adjacent state.
Composition notes:
- Place the button close to the thing it affects.
- Keep the action narrowly scoped.
Trade-offs:
- Very compact.
- Easy to overuse in forms without enough context.
import type { CSSProperties } from 'react';
import { Icon, IconButton, Label, TextField, TextFieldInput } from '@vega-ui/react';
import { SearchIcon, XIcon } from '@vega-ui/icons';
import { FormEvent, useRef, useState } from 'react';
export default function InlineClearAction() {
const input = useRef<HTMLInputElement>(null);
const [query, setQuery] = useState('quarterly report');
const [submitted, setSubmitted] = useState('');
const clear = () => {
setQuery('');Navigational Icon Surface
When to use:
- Navigation needs icon-button visuals while preserving link semantics.
Composition notes:
- Use
asChildwith a real anchor. - Keep the destination obvious from the surrounding context and accessible label.
Trade-offs:
- Strong visual consistency.
- Easy to misuse for ambiguous navigation.
import { Icon, IconButton } from '@vega-ui/react';
import { BookOpenIcon, LifeBuoyIcon, RssIcon } from '@vega-ui/icons';
const links = [
{ href: '/docs', label: 'Documentation', icon: <BookOpenIcon /> },
{ href: '/support', label: 'Help center', icon: <LifeBuoyIcon /> },
{ href: '/blog/rss.xml', label: 'Blog RSS feed', icon: <RssIcon /> },
];
export default function NavigationalIconSurface() {
return (
<nav aria-label='Resources'>Comparison
Quick Decision Rule
Use IconButton when the action is compact, common, and already recognizable without visible text.
IconButton vs Button
Use IconButton when:
- space is constrained
- the action is common and recognizable
Use Button when:
- visible text improves clarity
Main trade-off: icon button is denser, while button is clearer.
IconButton vs Link
Use IconButton when:
- the interaction is an action
Use Link when:
- the interaction primarily navigates
Main trade-off: icon button is action semantics, while link is navigation semantics.
IconButton vs ButtonBase
Use IconButton when:
- the product explicitly wants the icon-button size and layout contract
Use ButtonBase when:
- a lower-level custom icon action surface is being built
Choose This Component When
- The action is icon-first and well understood.
- Space is constrained.
- The UI still needs a button-like action surface.
- the action should stay compact without becoming a generic low-level primitive
Do Not Choose This Component When
- The action meaning is unclear without visible text.
- The interaction primarily navigates.
- A regular button would improve comprehension.
Troubleshooting
Action Meaning Is Unclear
Symptom
Users see the icon but do not know what the action does.
Likely Cause
IconButton was used for an action that needs visible text or stronger context.
How To Verify
- Hide surrounding context and inspect whether the action is still obvious.
- Check whether the same icon has a stable meaning elsewhere in the product.
Fix
- Switch to
Buttonif visible text improves clarity. - Keep icon-only treatment for familiar actions.
Missing Accessible Name
Symptom
The button works visually but has no clear accessible label.
Likely Cause
No aria-label or equivalent supported labeling was provided.
How To Verify
- Inspect the rendered markup.
- Test with accessibility tooling or screen reader output.
Fix
- Provide an explicit accessible label.
Polymorphic IconButton Behaves Strangely
Symptom
The icon-button visuals render, but the child element does not support the intended semantics or props.
Likely Cause
asChild was used with an incompatible child element.
How To Verify
- Inspect the rendered child element.
- Check whether it matches the intended action or navigation semantics.
Fix
- Use a child that supports the intended behavior.
- Keep default rendering when polymorphism is unnecessary.