Skip to content

Button

A button component is a clickable element that triggers actions when clicked. It can contain text or icons, has different styles, and plays a role in user interaction and navigation.

Import

ts
import { Button } from '@johngerome/vue-ui'
import { Button } from '@johngerome/vue-ui'

Composition

We highly recommend creating a Button wrapper instead of utilizing the Button component directly. Doing so will provide you with the flexibility to customize its appearance effortlessly through themes or Tailwind classes. This approach ensures greater control and consistency in your design.

vue
<script lang="ts" setup>
import Button from '@/components/Button/Button.vue'
import { THEME, Props } from '@/components/Button/Button.vue'

defineProps<Props>()

const theme = {
  ...THEME,
  variants: {
    ...THEME.variants,
    primary: 'bg-red-500 hover:bg-red-600',
  },
}
</script>

<template>
  <Button :theme="theme" class="rounded-none">Button</Button>
</template>
<script lang="ts" setup>
import Button from '@/components/Button/Button.vue'
import { THEME, Props } from '@/components/Button/Button.vue'

defineProps<Props>()

const theme = {
  ...THEME,
  variants: {
    ...THEME.variants,
    primary: 'bg-red-500 hover:bg-red-600',
  },
}
</script>

<template>
  <Button :theme="theme" class="rounded-none">Button</Button>
</template>
vue
<template>
  <MyButton>Button</MyButton>
</template>
<template>
  <MyButton>Button</MyButton>
</template>
Preview

Variants

Use variant prop to change the appearance of the Button. Available variants are primary, outline, ghost ,or link.

Click me to view the code
vue
<Button>Button</Button>
<Button variant="outline">Button</Button>
<Button variant="ghost">Button</Button>
<Button variant="link">Button</Button>
<Button>Button</Button>
<Button variant="outline">Button</Button>
<Button variant="ghost">Button</Button>
<Button variant="link">Button</Button>

Sizes

Use the size props to change the size of the Button. Available sizes are sm, md, lg, xl or 2xl

Click me to view the code
vue
<Button size="sm">Button</Button>
<Button size="md">Button</Button>
<Button size="lg">Button</Button>
<Button size="xl">Button</Button>
<Button size="2xl">Button</Button>
<Button size="sm">Button</Button>
<Button size="md">Button</Button>
<Button size="lg">Button</Button>
<Button size="xl">Button</Button>
<Button size="2xl">Button</Button>

Loading

Pass the is-loading props to show its loading state. To override loading icon use template #loading.

Click me to view the code
vue
<Button is-loading>Submitting</Button>
<Button class="flex-row-reverse space-x-0" is-loading>
  <span class="mr-2">Submitting</span>
</Button>
<Button is-loading></Button>
<Button is-loading>
  <span class="mr-3">Submitting</span>
  <template #loading>
    <Icon icon="eos-icons:three-dots-loading" class="text-3xl" />
  </template>
</Button>
<Button is-disabled>
  <span>Submitting</span>
  <Icon icon="eos-icons:three-dots-loading" class="text-3xl" />
</Button>
<Button is-loading>Submitting</Button>
<Button class="flex-row-reverse space-x-0" is-loading>
  <span class="mr-2">Submitting</span>
</Button>
<Button is-loading></Button>
<Button is-loading>
  <span class="mr-3">Submitting</span>
  <template #loading>
    <Icon icon="eos-icons:three-dots-loading" class="text-3xl" />
  </template>
</Button>
<Button is-disabled>
  <span>Submitting</span>
  <Icon icon="eos-icons:three-dots-loading" class="text-3xl" />
</Button>

Theme

ts
export const THEME = {
  disabled: 'opacity-50 cursor-not-allowed',
  variants: {
    primary: 'bg-primary text-gray-100 hover:bg-primary/90',
    outline:
      'border border-primary/30 text-primary hover:bg-primary hover:text-gray-100',
    ghost: 'text-primary hover:bg-primary/10',
    link: 'text-primary hover:underline',
  },
  sizes: {
    sm: 'px-2 py-1 text-xs rounded h-6',
    md: 'py-2 px-3 text-base rounded-md h-10',
    lg: 'p-3 text-lg rounded-md h-13',
    xl: 'p-4 text-xl rounded-lg h-16',
    '2xl': 'p-6 text-xl rounded-lg h-19',
  },
  loading: {
    sm: 'text-sm',
    md: 'text-lg',
    lg: 'text-xl',
    xl: 'text-2xl',
    '2xl': 'text-3xl',
  },
}
export const THEME = {
  disabled: 'opacity-50 cursor-not-allowed',
  variants: {
    primary: 'bg-primary text-gray-100 hover:bg-primary/90',
    outline:
      'border border-primary/30 text-primary hover:bg-primary hover:text-gray-100',
    ghost: 'text-primary hover:bg-primary/10',
    link: 'text-primary hover:underline',
  },
  sizes: {
    sm: 'px-2 py-1 text-xs rounded h-6',
    md: 'py-2 px-3 text-base rounded-md h-10',
    lg: 'p-3 text-lg rounded-md h-13',
    xl: 'p-4 text-xl rounded-lg h-16',
    '2xl': 'p-6 text-xl rounded-lg h-19',
  },
  loading: {
    sm: 'text-sm',
    md: 'text-lg',
    lg: 'text-xl',
    xl: 'text-2xl',
    '2xl': 'text-3xl',
  },
}

Props

ts
export type Props = {
  theme?: typeof THEME
  size?: keyof (typeof THEME)['sizes']
  variant?: keyof (typeof THEME)['variants']
  isDisabled?: boolean
  isLoading?: boolean
}
export type Props = {
  theme?: typeof THEME
  size?: keyof (typeof THEME)['sizes']
  variant?: keyof (typeof THEME)['variants']
  isDisabled?: boolean
  isLoading?: boolean
}