Skip to content
v2.5.0
English
Русский
Documentation

ButtonBase

ButtonBase is the low-level action primitive behind Button and IconButton.

Patterns

Shared Action Primitive

When to use: Build a product-specific action wrapper that still inherits VegaUI button styling.

Composition notes: Wrap ButtonBase in a local component and keep variant, appearance, and type explicit.

Trade-offs: You gain flexibility, but also take responsibility for accessible naming, layout, and semantic correctness.

shared-action-primitive.tsx · 67 lines
import { ButtonBase, type ButtonBaseProps, Icon } from '@vega-ui/react';
import { BoldIcon, ItalicIcon, UnderlineIcon } from '@vega-ui/icons';
import { useState } from 'react';

function ToolbarAction({ style, ...props }: ButtonBaseProps) {
  return (
    <ButtonBase
      type='button'
      variant='secondary'
      appearance='transparent'
      style={{ display: 'flex', padding: 'var(--spacing-3)', borderRadius: 'var(--radius-2)', ...style }}
      {...props}

Polymorphic Navigation Action

When to use: Render a navigation target that should visually look like a button.

Composition notes: Use asChild with exactly one anchor or router link child.

Trade-offs: The result keeps link semantics, so keyboard behavior and announcements differ from a native button.

polymorphic-navigation-action.tsx · 23 lines
import { ButtonBase, Icon } from '@vega-ui/react';
import { UsersIcon } from '@vega-ui/icons';

export default function PolymorphicNavigationAction() {
  return (
    <ButtonBase asChild variant='secondary' appearance='ghost'>
      <a
        href='/settings/members'
        style={{
          display: 'inline-flex',
          alignItems: 'center',
          gap: 'var(--spacing-4)',

Comparison

Quick Decision Rule

Choose ButtonBase only when the product needs the lowest shared action primitive. For normal product buttons, prefer Button or IconButton.

ButtonBase vs Button

Use ButtonBase when you need raw action styling with custom structure.

Use Button when product code should express a standard text button with the higher-level public API.

ButtonBase vs IconButton

Use ButtonBase when icon-only layout is custom or not the main intent.

Use IconButton when the action is primarily icon-first and should follow the icon-button size contract.

Use ButtonBase when the interaction is an action.

Use Link when the interaction is navigation and should keep link semantics.

Choose This Component When

  • a custom action component still needs VegaUI button styling
  • asChild is necessary for a router or anchor primitive
  • higher-level button layout APIs would get in the way

Do Not Choose This Component When

  • the product just needs a standard button
  • the interaction is clearly a text link
  • consumers should not have to reason about low-level semantics and type

Troubleshooting

The Button Submits A Form Unexpectedly

Symptom

Clicking the action submits the surrounding form even though the UI intended a normal button.

Likely Cause

type was not set explicitly and the browser default behaved like a submit action in that context.

How To Verify

  • render the button inside the real form
  • click it without any submit-specific intent
  • confirm whether the form submit handler fires

Fix

Set type='button' for non-submit actions.

The Action Looks Right But Keyboard Semantics Feel Wrong

Symptom

The element looks like a button, but keyboard behavior or screen-reader output follows link semantics.

Likely Cause

asChild rendered an anchor or router link, so the final element kept link semantics.

How To Verify

  • inspect the final DOM tag
  • test keyboard activation with Enter and Space
  • check screen-reader announcements

Fix

Use a native button when the interaction is an action, not navigation.

Icon-Only Content Is Not Announced Clearly

Symptom

The action is visible, but assistive technology does not expose a meaningful name.

Likely Cause

The button only contains an icon and no aria-label was provided.

How To Verify

  • inspect the accessible name in browser accessibility tools
  • test the button with a screen reader

Fix

Add an explicit aria-label or visible text content.