@todovue/tv-button
v1.2.6
Published
A customizable button component for TODOvue, supporting multiple variants, sizes, and icon modes.
Maintainers
Readme
TODOvue Button (TvButton)
A flexible, framework‑agnostic Vue 3 button component with variants, sizes, icons, loading state, and customization utilities. Ship it in Single Page Apps or Server-Side Rendered (SSR) environments (e.g. Nuxt 3) with zero DOM assumptions.
Demo: https://ui.todovue.blog/button/
Table of Contents
- Features
- Installation
- Quick Start (SPA)
- Style usage
- Nuxt 4 / SSR Usage
- Component Registration Options
- Props
- Events
- Icons
- Customization (Styles / Theming)
- Icon-only & Variant Notes
- Accessibility
- SSR Notes
- Development
- Contributing
- License
Features
- Variants: primary, secondary, success, info, warning, error
- Sizes: sm, md, lg, full-width option
- Icon support (pre-bundled SVG set via
import.meta.glob) - Icon-only and pure icon modes (
type="icon"+iconOnly) - Loading state with spinner
- Custom inline style override via
customStyle - Emits both a custom event and the native click
- Works in SPA and SSR (Nuxt 3) contexts
- Tree-shake friendly (Vue marked external in library build)
Installation
Using npm:
npm install @todovue/tv-buttonUsing yarn:
yarn add @todovue/tv-buttonUsing pnpm:
pnpm add @todovue/tv-buttonQuick Start (SPA)
Global registration (main.js / main.ts):
import { createApp } from 'vue'
import App from './App.vue'
import '@todovue/tv-button/style.css'
import TvButton from '@todovue/tv-button'
createApp(App)
.use(TvButton) // enables <TvButton /> globally
.mount('#app')Local import inside a component:
<script setup>
import '@todovue/tv-button/style.css'
import { TvButton } from '@todovue/tv-button'
function onSubmit() {
console.log('Clicked')
}
</script>
<template>
<TvButton variant="success" icon="check" @click-button="onSubmit">Submit</TvButton>
</template>Style usage
Vue 3 SPA with Vite
// main.ts
import { createApp } from 'vue'
import App from './App.vue'
import '@todovue/tv-button/style.css'
import { TvButton } from '@todovue/tv-button'
const app = createApp(App)
app.component('TvButton', TvButton)
app.mount('#app')Nuxt 3/4
// nuxt.config.ts
export default defineNuxtConfig({
modules: [
'@todovue/tv-button/nuxt'
]
})Nuxt 4 / SSR Usage
Create a plugin file: plugins/tv-button.client.ts (client-only is fine, or without suffix for SSR as it is safe):
import { defineNuxtPlugin } from '#app'
import TvButton from '@todovue/tv-button'
export default defineNuxtPlugin(nuxtApp => {
nuxtApp.vueApp.use(TvButton)
})Use anywhere:
<TvButton outlined icon="info">Details</TvButton>Optional direct import (no plugin):
<script setup>
import { TvButton } from '@todovue/tv-button'
</script>Component Registration Options
| Approach | When to use |
|-------------------------------------------------------------------|------------------------------------------------|
| Global via app.use(TvButton) | Many usages across app / design system install |
| Local named import { TvButton } | Isolated / code-split contexts |
| Direct default import import TvButton from '@todovue/tv-button' | Single usage or manual registration |
Props
All boolean style props have two interchangeable forms: a long form (isSomething) and a short alias.
| Prop | Type | Default | Description |
|--------------|-------------------------------------------|-----------|--------------------------------------------------------|
| buttonText | string | '' | Optional text (alternative to slot). |
| variant | 'primary' | 'secondary' | 'success' ... | 'primary' | Visual style variant. |
| size | 'sm' | 'md' | 'lg' | 'md' | Button size. |
| customStyle | object | {} | Inline style overrides ({ backgroundColor, color }). |
| icon | string | null | Name of bundled icon. |
| iconColor | string | 'white' | Icon color override. |
| iconPosition | 'left' | 'right' | 'right' | Icon position relative to text. |
| type | 'button' | 'submit' | 'reset' | 'icon' | 'button' | Native button type. Use 'icon' for icon-only styling. |
| ariaLabel | string | '' | Accessibility label (required if no text / icon-only). |
| iconOnly | boolean | false | Renders only the icon (no padding/background). |
| outlined | boolean | false | Outlined style. |
| rounded | boolean | false | Rounded corners. |
| disabled | boolean | false | Disables interaction. |
| loading | boolean | false | Shows spinner & disables. |
| full | boolean | false | Full width. |
| text | boolean | false | Text (minimal) style. |
| href | string | null | URL for native anchor tag. |
| to | string | object | null | Route for RouterLink / NuxtLink. |
| target | string | null | Anchor target (e.g. '_blank'). |
| rel | string | null | Anchor rel attribute. |
Note: Because
typeis bound to the native<button type="...">, usingtype="icon"produces a non-standard button attribute. This does not break rendering but is semantically incorrect in forms. A future release will introducevariantand keephtmlTypeseparate (see Roadmap).
Events
| Event name (kebab) | Emits (camel) | Description |
|--------------------|---------------|---------------------------------------------|
| click-button | clickButton | Custom semantic click event. |
| click | click | Native passthrough (also emitted manually). |
Usage:
<TvButton @click-button="onAction" />
<TvButton @click="onNative" />Icons
Set with the icon prop. Available names:
account, add-user, alert, arrow-down, arrow-left, arrow-right, arrow-up, block, calendar, cancel, check, clone, dark, download, edit, external-link, favorite, filter, help, info, light, loading, lock, login, logout, menu, minus, notification, plus, remove, search, settings, share, star, todovue, unlock, update, view double-arrow-left, double-arrow-right, home, dots-vertical, eye-off, trash, upload, dashboard, folder, link, mail and save.
Example:
<TvButton icon="check" variant="success">Saved</TvButton>
<TvButton icon="info" iconPosition="left" outlined>Info</TvButton>Customization (Styles / Theming)
Inline overrides via customStyle:
<TvButton :customStyle="{ backgroundColor: '#0f2e5b', color: '#fff' }">Branded</TvButton>Outlined variant adapts automatically:
<TvButton outlined :customStyle="{ backgroundColor: '#ff4081', color: '#fff' }">Pink Outline</TvButton>A subtle hover darkening is auto-generated when
customStyle.backgroundColorexists.
Icon-only & Variant Notes
Pure icon button:
<TvButton type="icon" icon="edit" />Inline icon-only action (no background / padding):
<TvButton type="icon" icon="edit" :iconOnly="true" aria-label="Edit item" />Loading state:
<TvButton loading icon="download">Processing...</TvButton>Link usage:
<!-- Native anchor -->
<TvButton href="https://todovvue.blog" target="_blank">External Link</TvButton>
<!-- Router link -->
<TvButton to="/dashboard">Go to Dashboard</TvButton>Accessibility
- Always provide visible text OR
aria-label. - Mandatory: add
aria-labelwhen usingiconOnlyor when slot content is empty. - Disabled state uses both
disabledattribute and styling classes.
SSR Notes
- No direct DOM (
window/document) access in source → safe for SSR. - Styles are now served from a separate CSS file generated by Vite (
dist/tv-button.css). You need to import it explicitly in your app (SPA or Nuxt) using@todovue/tv-button/style.css. - SVG icons are bundled via Vite's
import.meta.glob(works in Vite + Nuxt).
Development
git clone https://github.com/TODOvue/tv-button.git
cd tv-button
yarn install
yarn dev # run demo playground
yarn build # build libraryLocal demo served from Vite using index.html + src/demo examples.
Contributing
PRs and issues welcome. See CONTRIBUTING.md and CODE_OF_CONDUCT.md.
License
MIT © TODOvue
Attributions
Crafted for the TODOvue component ecosystem
