Skip to main content

Import

import { button, buttonGroup, primaryButton, dangerButton, outlineButton } from '@frontmcp/ui';

Basic Usage

// Primary button (default)
const html = button('Click Me');

// With variant
const secondary = button('Save', { variant: 'secondary' });
const danger = button('Delete', { variant: 'danger' });

Variants

Seven button variants for different purposes:
  • primary - Main actions
  • secondary - Secondary actions
  • outline - Bordered, less prominent
  • ghost - Text only, no background
  • danger - Destructive actions
  • success - Positive actions
  • link - Looks like a link

Shorthand Functions

import { primaryButton, secondaryButton, outlineButton, ghostButton, dangerButton, linkButton } from '@frontmcp/ui';

primaryButton('Submit')
dangerButton('Delete')
outlineButton('Cancel')

Sizes

Five size options: xs, sm, md (default), lg, xl.
button('Extra Small', { size: 'xs' })
button('Small', { size: 'sm' })
button('Medium', { size: 'md' })
button('Large', { size: 'lg' })
button('Extra Large', { size: 'xl' })

States

Loading State

const html = button('Saving...', {
  loading: true,
  disabled: true,
});
The loading state shows a spinner and visually indicates the button is busy.

Disabled State

const html = button('Unavailable', { disabled: true });

Full Width

const html = button('Full Width Button', { fullWidth: true });

Icons

Add icons before or after the button text:
// Icon before text
const html = button('Download', {
  iconBefore: '<svg class="w-4 h-4" ...>...</svg>',
});

// Icon after text
const html = button('Next', {
  iconAfter: '<svg class="w-4 h-4" ...>...</svg>',
});

// Icon only (accessibility: text becomes aria-label)
const html = button('Settings', {
  iconBefore: '<svg class="w-5 h-5" ...>...</svg>',
  iconOnly: true,
});
The iconBefore and iconAfter options accept raw HTML for SVG icons. Only use trusted content (e.g., icon library output). Never pass user input.
Render as an anchor tag with href:
const html = button('Visit Site', {
  href: 'https://example.com',
  target: '_blank', // Opens in new tab (adds rel="noopener noreferrer")
});
Only safe protocols are allowed: http://, https://, /, #, mailto:, tel:. Dangerous protocols like javascript: are blocked.

HTMX Integration

Add dynamic behavior without JavaScript:
// Load content on click
const html = button('Load More', {
  htmx: {
    get: '/api/items?page=2',
    target: '#items-list',
    swap: 'beforeend',
  },
});

// Submit form data
const submit = button('Submit', {
  htmx: {
    post: '/api/submit',
    target: '#result',
    swap: 'innerHTML',
  },
});

// With confirmation
const deleteBtn = button('Delete', {
  variant: 'danger',
  htmx: {
    delete: '/api/item/123',
    target: '#item-123',
    swap: 'outerHTML',
    confirm: 'Are you sure you want to delete this?',
  },
});

// With loading indicator
const loadBtn = button('Fetch Data', {
  htmx: {
    get: '/api/data',
    target: '#result',
    indicator: '#loading-spinner',
  },
});

HTMX Options

OptionDescription
getHTTP GET request URL
postHTTP POST request URL
putHTTP PUT request URL
deleteHTTP DELETE request URL
targetCSS selector for response target
swapHow to swap content
triggerEvent that triggers request
confirmConfirmation dialog text
indicatorLoading indicator selector

Button Groups

Group related buttons together:
import { button, buttonGroup } from '@frontmcp/ui';

// Horizontal group (default)
const group = buttonGroup([
  button('Edit', { variant: 'outline' }),
  button('Duplicate', { variant: 'outline' }),
  button('Delete', { variant: 'danger' }),
]);

// Attached buttons (no gap, rounded ends only)
const attached = buttonGroup([
  button('Left'),
  button('Center'),
  button('Right'),
], { attached: true });

// Vertical group
const vertical = buttonGroup([
  button('Option 1'),
  button('Option 2'),
  button('Option 3'),
], { direction: 'vertical' });

// Custom gap
const spaced = buttonGroup([
  button('Save'),
  button('Cancel', { variant: 'outline' }),
], { gap: 'lg' });

ButtonGroup Options

OptionTypeDefaultDescription
attachedbooleanfalseJoin buttons with no gap
direction'horizontal' | 'vertical''horizontal'Layout direction
gap'sm' | 'md' | 'lg''md'Space between buttons
classNamestring-Additional CSS classes

Data Attributes

Add custom data attributes:
const html = button('Track Click', {
  data: {
    'analytics-id': 'btn-submit',
    'action': 'signup',
  },
});
// Renders: data-analytics-id="btn-submit" data-action="signup"

API Reference

button(text, options?)

ParameterTypeDescription
textstringButton label (used as aria-label for icon-only)
optionsButtonOptionsConfiguration options

ButtonOptions

OptionTypeDefaultDescription
variant'primary' | 'secondary' | 'outline' | 'ghost' | 'danger' | 'success' | 'link''primary'Visual style
size'xs' | 'sm' | 'md' | 'lg' | 'xl''md'Button size
type'button' | 'submit' | 'reset''button'HTML button type
disabledbooleanfalseDisable the button
loadingbooleanfalseShow loading spinner
fullWidthbooleanfalseFull container width
iconBeforestring-HTML for icon before text
iconAfterstring-HTML for icon after text
iconOnlybooleanfalseHide text, show icon only
classNamestring-Additional CSS classes
idstring-Button ID
namestring-Form field name
valuestring-Form field value
hrefstring-Link URL (renders as <a>)
targetstring-Link target
htmxobject-HTMX attributes
dataRecord<string, string>-Data attributes
ariaLabelstring-Accessibility label

Returns

string - HTML string for the button element.