ButtonBase Component
The ButtonBase
component is a versatile button component designed with Vue 3 and Tailwind CSS. It includes customizable color options, size variants, and additional configuration options to adapt to different use cases.
Basic Usage
Import and use ButtonBase
in your Vue components as follows:
<template>
<ButtonBase label="Click Me" />
</template>
<script setup>
import { ButtonBase } from '@robuust-digital/vue-components';
</script>
Props
Below are the props supported by ButtonBase
, which allow you to customize its appearance and behavior:
Prop | Type | Default | Description |
---|---|---|---|
as | String , Object , Function | button | Defines the element type or component to render. |
bindAs | String | '' | In some cases (e.g. when using Inertia links) where you need to render a different element, you can use this prop to bind the component to a different element. |
label | String | '' | Sets the text label for the button. |
icon | Object , Function | null | Specifies an icon to display within the button. @heroicons/vue can be used, or you can import your own .svg files. |
iconLeft | Boolean | false | Displays the icon on the left side of the button text if true. |
size | String | base | Specifies the button size. Options: sm and base . |
spinning | Boolean | false | Shows a loading spinner in place of the icon when true. |
color | String | primary | Sets the button's color variant. Accepts predefined values and custom formats (red-soft , primary and custom-* ). Learn more about color variants in the next section. |
iconOnly | Boolean | false | Renders a button with only an icon. When enabled, an icon should be provided either via the icon prop or icon slot. |
Color Variants
The color
prop supports both predefined and custom values. Default colors include:
primary
secondary
tertiary
light
dark
red
red-soft
yellow
yellow-soft
green
green-soft
blue
blue-soft
clear
custom-*
Custom Colors
If you don't find a color variant that suits your needs, you can create custom color variants.
Use custom-*
color formats to add unique colors directly from your tailwind.config.js
file.
Slots
Default Slot
Provides a way to customize the button content with access to the label prop:
<template>
<ButtonBase label="Click Me" v-slot="{ label }">
{{ label }} <!-- Access to label prop -->
</ButtonBase>
</template>
Icon Slot
Customize the icon section with access to the icon prop:
<template>
<ButtonBase label="Click Me">
<template #icon="{ icon }">
<div class="flex items-center gap-1">
<Component :is="icon" class="size-4" /> <!-- Access to icon prop -->
<StarIcon class="size-4" />
</div>
</template>
</ButtonBase>
</template>
Icon Placement
The icon slot respects the iconLeft
prop, so you can control whether your custom icon content appears on the left or right side of the button text.
Spinner Slot
Customize the spinner with access to the spinning state:
<template label="Save Changes">
<ButtonBase :spinning="isLoading">
<template #spinner="{ spinning }">
<div v-if="spinning" class="custom-loader">
<CustomSpinnerComponent />
</div>
</template>
</ButtonBase>
</template>
Spinner Visibility
The spinner slot content will only be visible when the spinning
prop is true, replacing either the icon (if present) or appearing before the button text.
Customization with Tailwind CSS
To customize the button
styles globally, extend your Tailwind configuration. Example:
// tailwind.config.js
import components from '@robuust-digital/vue-components/tailwind';
export default {
// ...
theme: {
extend: {
components: (theme) => ({
button: {
'--rvc-button-height': theme('height.9'),
'--rvc-button-border-width': theme('borderWidth.DEFAULT'),
'--rvc-button-padding-x': theme('padding.3'),
'--rvc-button-gap': theme('gap[1.5]'),
'--rvc-button-border-radius': theme('borderRadius.md'),
'--rvc-button-font-weight': theme('fontWeight.semibold'),
'--rvc-button-font-size': theme('fontSize.base.0'),
'--rvc-button-transition-property': theme('transitionProperty.colors'),
'--rvc-button-transition-duration': theme('transitionDuration.DEFAULT'),
'--rvc-button-transition-timing-function': theme('transitionTimingFunction.DEFAULT'),
'--rvc-button-icon-size': theme('width.5'),
'--rvc-button-icon-loading-size': theme('width.4'),
'--rvc-button-icon-loading-animation': theme('animation.spin'),
'--rvc-button-box-shadow': 'none',
'--rvc-button-bg-color': '#d9ff00',
'--rvc-button-color': '#000',
'--rvc-button-bg-color-hover': '#c1e012',
'--rvc-button-color-hover': '#000',
'--rvc-button-border-color': theme('colors.transparent'),
'--rvc-button-border-color-hover': theme('colors.transparent'),
'--rvc-button-icon-color': theme('colors.slate.500'),
'--rvc-button-icon-color-hover': theme('colors.slate.950'),
},
}),
},
},
plugins: [components],
};
Full Tailwind CSS button
component configuration options can be found here.
Sizes
The ButtonBase component supports different sizes through the size
prop:
Base size (default)
Show code
<ButtonBase color="primary" label="Base Button" />
Small size
Show code
<ButtonBase color="primary" size="sm" label="Small Button" />
Examples
Basic Colors
Show code
<ButtonBase color="primary" label="Primary" />
<ButtonBase color="secondary" label="Secondary" />
<ButtonBase color="tertiary" label="Tertiary" />
<ButtonBase color="light" label="Light" />
<ButtonBase color="dark" label="Dark" />
System Colors
Show code
<ButtonBase color="green" label="Green" />
<ButtonBase color="red" label="Red" />
<ButtonBase color="yellow" label="Yellow" />
<ButtonBase color="blue" label="Blue" />
Soft System Colors
Show code
<ButtonBase color="green-soft" label="Green Soft" />
<ButtonBase color="red-soft" label="Red Soft" />
<ButtonBase color="yellow-soft" label="Yellow Soft" />
<ButtonBase color="blue-soft" label="Blue Soft" />
Clear Button
Show code
<ButtonBase color="clear" label="Clear Button" />
<ButtonBase color="clear" label="Clear Button with Icon" icon-left :icon="BeakerIcon" />
<ButtonBase color="clear" icon-only label="Clear Button with Icon" :icon="BeakerIcon" />
Button with Icon
Show code
<ButtonBase label="Button Icon" :icon="BeakerIcon" />
<ButtonBase label="Delete" color="red-soft" :icon="TrashIcon" icon-left />
Loading Button
Use spinning
to show a loading spinner:
Show code
<ButtonBase color="tertiary" label="Loading Button" :icon="BeakerIcon" spinning />
<ButtonBase color="dark" size="sm" label="Loading Button" :icon="BeakerIcon" spinning />
Custom Button
Show code
<ButtonBase color="custom-foo" label="Custom Button" />
export default {
// tailwind.config.js ...
custom: {
foo: {
'--rvc-button-border-radius': theme('borderRadius.full'),
'--rvc-button-bg-color': theme('colors.pink.200'),
'--rvc-button-color': theme('colors.pink.800'),
'--rvc-button-bg-color-hover': theme('colors.pink.300'),
'--rvc-button-color-hover': theme('colors.pink.900'),
'--rvc-button-icon-color': theme('colors.pink.700'),
'--rvc-button-icon-color-hover': theme('colors.red.500'),
},
},
// ...
}
Icon Only Button
Show code
<ButtonBase label="Icon Only Button" color="green-soft" :icon="BeakerIcon" icon-only />
Tailwind Config
Full Tailwind CSS button
component configuration options can be found below:
// tailwind.config.js
import components from '@robuust-digital/vue-components/tailwind';
export default {
// ...
theme: {
extend: {
components: (theme) => ({
button: {
// Available variables you can override:
'--rvc-button-height': theme('height.9'),
'--rvc-button-border-width': theme('borderWidth.DEFAULT'),
'--rvc-button-padding-x': theme('padding.3'),
'--rvc-button-gap': theme('gap[1.5]'),
'--rvc-button-border-radius': theme('borderRadius.md'),
'--rvc-button-font-weight': theme('fontWeight.semibold'),
'--rvc-button-font-size': theme('fontSize.base.0'),
'--rvc-button-transition-property': theme('transitionProperty.colors'),
'--rvc-button-transition-duration': theme('transitionDuration.DEFAULT'),
'--rvc-button-transition-timing-function': theme('transitionTimingFunction.DEFAULT'),
'--rvc-button-icon-size': theme('width.5'),
'--rvc-button-icon-loading-size': theme('width.4'),
'--rvc-button-icon-loading-animation': theme('animation.spin'),
'--rvc-button-box-shadow': 'none',
// Color variables you can override:
'--rvc-button-bg-color': '#d9ff00',
'--rvc-button-color': '#000',
'--rvc-button-bg-color-hover': '#caf400',
'--rvc-button-color-hover': '#000',
'--rvc-button-border-color': theme('colors.transparent'),
'--rvc-button-border-color-hover': theme('colors.transparent'),
'--rvc-button-icon-color': theme('colors.slate.500'),
'--rvc-button-icon-color-hover': theme('colors.slate.950'),
// Color variants
secondary: {
'--rvc-button-bg-color': '#4f46e5',
'--rvc-button-color': '#fff',
'--rvc-button-bg-color-hover': '#6366f1',
'--rvc-button-color-hover': '#fff',
'--rvc-button-icon-color': theme('colors.slate.300'),
'--rvc-button-icon-color-hover': '#fff',
},
tertiary: {
'--rvc-button-bg-color': '#475569',
'--rvc-button-color': '#fff',
'--rvc-button-bg-color-hover': '#64748b',
'--rvc-button-color-hover': '#fff',
'--rvc-button-icon-color': theme('colors.slate.300'),
'--rvc-button-icon-color-hover': '#fff',
},
light: {
'--rvc-button-bg-color': theme('colors.white'),
'--rvc-button-color': theme('colors.black'),
'--rvc-button-bg-color-hover': theme('colors.slate.50'),
'--rvc-button-color-hover': theme('colors.black'),
'--rvc-button-border-color': theme('colors.slate.200'),
'--rvc-button-border-color-hover': theme('colors.slate.200'),
},
dark: {
'--rvc-button-bg-color': theme('colors.slate.950'),
'--rvc-button-color': theme('colors.white'),
'--rvc-button-bg-color-hover': theme('colors.slate.800'),
'--rvc-button-color-hover': theme('colors.white'),
'--rvc-button-icon-color': theme('colors.slate.300'),
'--rvc-button-icon-color-hover': theme('colors.white'),
},
red: {
'--rvc-button-bg-color': theme('colors.red.600'),
'--rvc-button-color': theme('colors.white'),
'--rvc-button-bg-color-hover': theme('colors.red.500'),
'--rvc-button-color-hover': theme('colors.white'),
'--rvc-button-icon-color': theme('colors.slate.300'),
'--rvc-button-icon-color-hover': theme('colors.white'),
},
'red-soft': {
'--rvc-button-bg-color': theme('colors.red.50'),
'--rvc-button-color': theme('colors.red.700'),
'--rvc-button-bg-color-hover': theme('colors.red.200'),
'--rvc-button-color-hover': theme('colors.red.700'),
'--rvc-button-border-color': theme('colors.red.200'),
'--rvc-button-border-color-hover': theme('colors.red.200'),
'--rvc-button-icon-color': theme('colors.red.500'),
'--rvc-button-icon-color-hover': theme('colors.red.700'),
},
yellow: {
'--rvc-button-bg-color': theme('colors.yellow.300'),
'--rvc-button-color': theme('colors.slate.950'),
'--rvc-button-bg-color-hover': theme('colors.yellow.400'),
'--rvc-button-color-hover': theme('colors.slate.950'),
},
'yellow-soft': {
'--rvc-button-bg-color': theme('colors.yellow.50'),
'--rvc-button-color': theme('colors.yellow.700'),
'--rvc-button-bg-color-hover': theme('colors.yellow.200'),
'--rvc-button-color-hover': theme('colors.yellow.700'),
'--rvc-button-border-color': theme('colors.yellow.200'),
'--rvc-button-border-color-hover': theme('colors.yellow.200'),
'--rvc-button-icon-color': theme('colors.yellow.500'),
'--rvc-button-icon-color-hover': theme('colors.yellow.700'),
},
green: {
'--rvc-button-bg-color': theme('colors.green.600'),
'--rvc-button-color': theme('colors.white'),
'--rvc-button-bg-color-hover': theme('colors.green.500'),
'--rvc-button-color-hover': theme('colors.white'),
'--rvc-button-icon-color': theme('colors.slate.300'),
'--rvc-button-icon-color-hover': theme('colors.white'),
},
'green-soft': {
'--rvc-button-bg-color': theme('colors.green.50'),
'--rvc-button-color': theme('colors.green.700'),
'--rvc-button-bg-color-hover': theme('colors.green.200'),
'--rvc-button-color-hover': theme('colors.green.700'),
'--rvc-button-border-color': theme('colors.green.200'),
'--rvc-button-border-color-hover': theme('colors.green.200'),
'--rvc-button-icon-color': theme('colors.green.500'),
'--rvc-button-icon-color-hover': theme('colors.green.700'),
},
blue: {
'--rvc-button-bg-color': theme('colors.blue.600'),
'--rvc-button-color': theme('colors.white'),
'--rvc-button-bg-color-hover': theme('colors.blue.500'),
'--rvc-button-color-hover': theme('colors.white'),
'--rvc-button-icon-color': theme('colors.slate.300'),
'--rvc-button-icon-color-hover': theme('colors.white'),
},
'blue-soft': {
'--rvc-button-bg-color': theme('colors.blue.50'),
'--rvc-button-color': theme('colors.blue.700'),
'--rvc-button-bg-color-hover': theme('colors.blue.200'),
'--rvc-button-color-hover': theme('colors.blue.700'),
'--rvc-button-border-color': theme('colors.blue.200'),
'--rvc-button-border-color-hover': theme('colors.blue.200'),
'--rvc-button-icon-color': theme('colors.blue.500'),
'--rvc-button-icon-color-hover': theme('colors.blue.700'),
},
clear: {
'--rvc-button-bg-color': theme('colors.transparent'),
'--rvc-button-color': theme('colors.indigo.600'),
'--rvc-button-bg-color-hover': theme('colors.transparent'),
'--rvc-button-color-hover': theme('colors.indigo.700'),
'--rvc-button-icon-color': theme('colors.indigo.600'),
'--rvc-button-icon-color-hover': theme('colors.indigo.700'),
},
// Size variants
sm: {
'--rvc-button-height': '1.875rem',
'--rvc-button-padding-x': theme('padding[2.5]'),
'--rvc-button-font-size': theme('fontSize.sm.0'),
'--rvc-button-icon-size': theme('width.4'),
'--rvc-button-icon-loading-size': theme('width.3'),
},
// You can also apply additional styles
'@apply whitespace-nowrap': {},
// or
display: 'none',
},
}),
},
},
plugins: [components],
};