Patterns
Inline Reference Link
When to use:
- Navigation belongs naturally inside a sentence or help copy.
Composition notes:
- Keep the linked words descriptive.
- Do not break reading flow with vague or overly long linked phrases.
Trade-offs:
- Strong for documentation and secondary navigation.
- Weaker for primary actions.
import { Link, Text } from '@vega-ui/react';
export default function BasicUsage() {
return (
<Text size={3} style={{ width: '100%' }}>
Exports include every invoice from the selected period. Read how we calculate{' '}
<Link href='/docs/billing/taxes'>VAT for EU customers</Link>{' '}
before sharing the file with your accountant.
</Text>
);
}Standalone Secondary Navigation
When to use:
- A page or panel needs one lightweight secondary navigation target.
Composition notes:
- Keep the link scannable and destination-oriented.
- Use surrounding copy when the destination context is not obvious.
Trade-offs:
- Light visual weight.
- Easier to overlook than a button.
import { Heading, Icon, Link } from '@vega-ui/react';
import { ArrowRightIcon } from '@vega-ui/icons';
import './examples.css';
const invoices = [
{ id: 'INV-2041', amount: '$1,240.00' },
{ id: 'INV-2040', amount: '$860.50' },
{ id: 'INV-2039', amount: '$2,115.00' },
];
export default function StandaloneNavigationLink() {
return (Router-Composed Link
When to use:
- The app uses a routing library and still wants VegaUI link styling.
Composition notes:
- Use
asChildwith a real router link component. - Preserve navigation semantics at the rendered root.
Trade-offs:
- Keeps styling consistent across routing layers.
- Requires the child component to support the expected semantics.
import { type AnchorHTMLAttributes, type MouseEvent, useState } from 'react';
import { Link } from '@vega-ui/react';
interface RouterLinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
to: string
onNavigate(to: string): void
}
function RouterLink({ to, onNavigate, onClick, ...props }: RouterLinkProps) {
const handleClick = (event: MouseEvent<HTMLAnchorElement>) => {
onClick?.(event);
event.preventDefault();Comparison
Quick Decision Rule
Use Link when the primary job is navigation.
Link vs Button
Use Link when:
- the interaction navigates to another page, route, or section
Use Button when:
- the interaction performs an action or mutates state
Main trade-off: link is navigation semantics, while button is action semantics.
Link vs Button asChild
Use Link when:
- plain text-link presentation is enough
Use Button asChild when:
- navigation should keep button visuals
Main trade-off: link stays lighter and more textual, while button-as-link adds stronger action styling.
Link vs Badge
Use Link when:
- the text should navigate somewhere
Use Badge when:
- the UI only needs compact metadata or status labeling
Choose This Component When
- The interaction primarily navigates.
- Text-link presentation fits the surrounding UI.
- Inline or secondary navigation is needed.
- the UI should read as navigation rather than command
Do Not Choose This Component When
- The interaction mutates state.
- A visible button surface is the better presentation.
- The link text does not clearly describe the destination.
Troubleshooting
Link Should Probably Be A Button
Symptom
The interaction looks fine, but the element performs an action instead of navigation.
Likely Cause
Link was chosen for something that mutates state or submits data.
How To Verify
- Ask whether the primary job is navigation or action.
- Check whether the interaction changes local or remote state.
Fix
- Use
Buttonfor actions. - Keep
Linkfor real navigation.
Link Text Is Too Vague
Symptom
Users cannot tell where the link goes from the text alone.
Likely Cause
The visible copy is generic, such as "Click here".
How To Verify
- Read the link text without surrounding explanation.
- Check whether the destination is still understandable.
Fix
- Rewrite the link text so it describes the destination or result clearly.
Router-Composed Link Loses Semantics
Symptom
The link looks correct but the rendered child no longer behaves like a link.
Likely Cause
asChild was used with a child that does not preserve link semantics.
How To Verify
- Inspect the rendered root element.
- Check whether it still behaves as a real link.
Fix
- Use a router component that preserves link-like rendering and behavior.
- Keep plain anchor rendering when polymorphism is unnecessary.