@changebot/widgets-vue
| Install | |
|---|---|
npm install @changebot/widgets-vue |
|
| Latest Version: | 0.5.0 |
| Vue: | 3 |
| License: | Apache-2.0 |
| Last Updated: | Aug 24, 2026 |
| Links: | GitHub · npm |
@changebot/widgets-vue
Vue wrapper components for Changebot - beautiful, customizable widgets for displaying product updates and changelogs to your users.
Installation
npm install @changebot/widgets-vue
Peer Dependencies
This package requires Vue 3.0.0 or later:
npm install vue
Quick Start
<script setup>
import {
ChangebotProvider,
ChangebotBadge,
ChangebotPanel
} from '@changebot/widgets-vue';
</script>
<template>
<!-- Provider can be placed anywhere - components don't need to be nested -->
<ChangebotProvider slug="your-team-slug" />
<header>
<h1>My App</h1>
<ChangebotBadge />
</header>
<ChangebotPanel mode="drawer-right" />
</template>
Components
ChangebotProvider
The provider component manages state and data fetching for all Changebot components. It listens at the document level, so components do not need to be nested inside it—they can be placed anywhere on the page.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
slug |
string |
required | Your Changebot team slug (from your Changebot dashboard) |
scope |
string |
"default" |
Scope identifier for isolating multiple instances |
Example
<template>
<!-- Components can be siblings - no nesting required -->
<ChangebotProvider slug="acme-corp" />
<ChangebotBadge />
<ChangebotPanel />
</template>
Multiple Instances
Use different scopes to run multiple independent instances:
<template>
<div>
<ChangebotProvider slug="team-a" scope="team-a">
<ChangebotBadge scope="team-a" />
<ChangebotPanel scope="team-a" />
</ChangebotProvider>
<ChangebotProvider slug="team-b" scope="team-b">
<ChangebotBadge scope="team-b" />
<ChangebotPanel scope="team-b" />
</ChangebotProvider>
</div>
</template>
ChangebotBadge
A badge component that displays the count of new, unread updates. Clicking the badge opens the associated panel.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
scope |
string |
"default" |
Scope to connect to (must match provider scope) |
theme |
Theme |
- | Fixed theme (see Theming section) |
light |
Theme |
- | Theme for light mode (auto-switches based on system preference) |
dark |
Theme |
- | Theme for dark mode (auto-switches based on system preference) |
indicator |
"count" | "dot" |
"count" |
Display style: show count number or dot only |
Example
<template>
<!-- Basic usage -->
<ChangebotBadge />
<!-- With theme -->
<ChangebotBadge theme="catppuccin-mocha" />
<!-- Show dot instead of count -->
<ChangebotBadge indicator="dot" />
<!-- Auto-switching theme -->
<ChangebotBadge
light="catppuccin-latte"
dark="catppuccin-mocha"
/>
</template>
ChangebotPanel
A panel component that displays your product updates. Can be displayed as a drawer (left/right) or centered modal.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
scope |
string |
"default" |
Scope to connect to (must match provider scope) |
mode |
"drawer-left" | "drawer-right" | "modal" |
"drawer-right" |
Display mode |
theme |
Theme |
- | Fixed theme (see Theming section) |
light |
Theme |
- | Theme for light mode (auto-switches based on system preference) |
dark |
Theme |
- | Theme for dark mode (auto-switches based on system preference) |
Methods
Use template refs to access methods:
<script setup>
import { ref } from 'vue';
import { ChangebotPanel } from '@changebot/widgets-vue';
const panelRef = ref(null);
const openPanel = async () => {
await panelRef.value?.open();
};
const closePanel = async () => {
await panelRef.value?.close();
};
// Set updates programmatically (for standalone usage)
const setUpdates = async (updates) => {
await panelRef.value?.setUpdates(updates);
};
</script>
<template>
<button @click="openPanel">Show Updates</button>
<ChangebotPanel
ref="panelRef"
mode="drawer-right"
theme="nord"
/>
</template>
Example
<script setup>
import { ref } from 'vue';
import { ChangebotPanel } from '@changebot/widgets-vue';
const panelRef = ref(null);
const handleOpenPanel = async () => {
await panelRef.value?.open();
};
</script>
<template>
<button @click="handleOpenPanel">Show Updates</button>
<ChangebotPanel
ref="panelRef"
mode="drawer-right"
theme="nord"
/>
</template>
ChangebotBanner
A banner component that displays a highlighted update at the top of your page. Automatically shows the most recent update marked with highlight_target="banner".
Props
| Prop | Type | Default | Description |
|---|---|---|---|
scope |
string |
"default" |
Scope to connect to (must match provider scope) |
theme |
Theme |
- | Fixed theme (see Theming section) |
light |
Theme |
- | Theme for light mode (auto-switches based on system preference) |
dark |
Theme |
- | Theme for dark mode (auto-switches based on system preference) |
Methods
<script setup>
import { ref } from 'vue';
const bannerRef = ref(null);
// Show banner with specific update
const showBanner = async (update) => {
await bannerRef.value?.show(update);
};
// Dismiss the banner
const dismissBanner = async () => {
await bannerRef.value?.dismiss();
};
// Toggle expanded state
const toggleBanner = async () => {
await bannerRef.value?.toggle();
};
</script>
<template>
<ChangebotBanner ref="bannerRef" theme="dracula" />
</template>
Example
<template>
<ChangebotBanner theme="dracula" />
</template>
ChangebotToast
A toast notification component that displays brief update notifications. Automatically shows the most recent update marked with highlight_target="toast".
Props
| Prop | Type | Default | Description |
|---|---|---|---|
scope |
string |
"default" |
Scope to connect to (must match provider scope) |
position |
"top-left" | "top-right" | "bottom-left" | "bottom-right" |
"bottom-right" |
Screen position for the toast |
theme |
Theme |
- | Fixed theme (see Theming section) |
light |
Theme |
- | Theme for light mode (auto-switches based on system preference) |
dark |
Theme |
- | Theme for dark mode (auto-switches based on system preference) |
Methods
<script setup>
import { ref } from 'vue';
const toastRef = ref(null);
// Show toast with specific update
const showToast = async (update) => {
await toastRef.value?.show(update);
};
// Dismiss the toast
const dismissToast = async () => {
await toastRef.value?.dismiss();
};
</script>
<template>
<ChangebotToast
ref="toastRef"
position="bottom-right"
theme="tokyo-night"
/>
</template>
Example
<template>
<ChangebotToast
position="bottom-right"
theme="tokyo-night"
/>
</template>
Theming
Changebot widgets include 15 beautiful pre-built themes:
Available Themes
- Catppuccin:
catppuccin-latte(light),catppuccin-frappe,catppuccin-macchiato,catppuccin-mocha(dark) - Gruvbox:
gruvbox-light,gruvbox-dark - Popular:
dracula,nord,tokyo-night,cyberpunk - Solarized:
solarized-light,solarized-dark - Everforest:
everforest-light,everforest-dark - Modern:
frost(clean, minimal light theme)
Using Themes
Fixed Theme
Use the theme prop for a theme that never changes:
<template>
<ChangebotPanel theme="catppuccin-mocha" />
</template>
Auto-Switching Theme
Use light and dark props to automatically switch based on user's system preference:
<template>
<ChangebotPanel
light="catppuccin-latte"
dark="catppuccin-mocha"
/>
</template>
Apply to All Components
<template>
<ChangebotProvider slug="acme">
<ChangebotBadge
light="gruvbox-light"
dark="gruvbox-dark"
/>
<ChangebotPanel
light="gruvbox-light"
dark="gruvbox-dark"
/>
<ChangebotBanner
light="gruvbox-light"
dark="gruvbox-dark"
/>
<ChangebotToast
light="gruvbox-light"
dark="gruvbox-dark"
/>
</ChangebotProvider>
</template>
Display Modes
The ChangebotPanel component supports three display modes:
drawer-right (default)
Slides in from the right side of the screen. Great for most applications.
<template>
<ChangebotPanel mode="drawer-right" />
</template>
drawer-left
Slides in from the left side of the screen. Useful when your navigation is on the right.
<template>
<ChangebotPanel mode="drawer-left" />
</template>
modal
Displays as a centered modal dialog with backdrop overlay. Best for focused, important updates.
<template>
<ChangebotPanel mode="modal" />
</template>
Advanced Usage
Standalone Usage (Without Provider)
Components can work independently without a provider for simple use cases:
Standalone Panel
<script setup>
import { ref } from 'vue';
import { ChangebotPanel } from '@changebot/widgets-vue';
const panelRef = ref(null);
const openWithUpdates = async () => {
await panelRef.value?.setUpdates([
{
id: 1,
title: 'New Feature',
content: '<p>Check out our new feature!</p>',
display_date: '2024-01-15',
published_at: '2024-01-15T10:00:00Z',
expires_on: null,
highlight_target: null,
hosted_url: null,
tags: [{ id: 1, name: 'Feature', color: '#3b82f6' }]
}
]);
await panelRef.value?.open();
};
</script>
<template>
<button @click="openWithUpdates">Show Updates</button>
<ChangebotPanel ref="panelRef" />
</template>
Complete Examples
Basic Setup with All Components
<script setup>
import {
ChangebotProvider,
ChangebotBadge,
ChangebotPanel,
ChangebotBanner,
ChangebotToast
} from '@changebot/widgets-vue';
</script>
<template>
<!-- Provider can be placed anywhere -->
<ChangebotProvider slug="acme-corp" />
<!-- Banner appears automatically for banner-highlighted updates -->
<ChangebotBanner theme="catppuccin-mocha" />
<header>
<h1>ACME Corp</h1>
<!-- Badge shows count of new updates -->
<ChangebotBadge theme="catppuccin-mocha" />
</header>
<main>
<!-- Your app content -->
</main>
<!-- Panel opens when badge is clicked -->
<ChangebotPanel
mode="drawer-right"
theme="catppuccin-mocha"
/>
<!-- Toast appears for toast-highlighted updates -->
<ChangebotToast
position="bottom-right"
theme="catppuccin-mocha"
/>
</template>
Responsive Theme Example
<script setup>
import {
ChangebotProvider,
ChangebotBadge,
ChangebotPanel
} from '@changebot/widgets-vue';
</script>
<template>
<!-- Automatically switches between light/dark based on system preference -->
<ChangebotProvider slug="acme-corp">
<header>
<h1>My App</h1>
<ChangebotBadge
light="catppuccin-latte"
dark="catppuccin-mocha"
/>
</header>
<ChangebotPanel
mode="drawer-right"
light="catppuccin-latte"
dark="catppuccin-mocha"
/>
</ChangebotProvider>
</template>
Multiple Scopes Example
<script setup>
import {
ChangebotProvider,
ChangebotBadge,
ChangebotPanel
} from '@changebot/widgets-vue';
</script>
<template>
<div>
<!-- Product Updates -->
<ChangebotProvider slug="product-updates" scope="product">
<section>
<h2>
Product News
<ChangebotBadge scope="product" theme="nord" />
</h2>
<ChangebotPanel scope="product" mode="drawer-right" theme="nord" />
</section>
</ChangebotProvider>
<!-- Company Announcements -->
<ChangebotProvider slug="company-news" scope="company">
<section>
<h2>
Company Announcements
<ChangebotBadge scope="company" theme="dracula" />
</h2>
<ChangebotPanel scope="company" mode="drawer-left" theme="dracula" />
</section>
</ChangebotProvider>
</div>
</template>
Programmatic Control Example
<script setup>
import { ref } from 'vue';
import {
ChangebotProvider,
ChangebotPanel
} from '@changebot/widgets-vue';
const panelRef = ref(null);
const showUpdates = async () => {
await panelRef.value?.open();
};
const hideUpdates = async () => {
await panelRef.value?.close();
};
</script>
<template>
<ChangebotProvider slug="acme-corp">
<div>
<button @click="showUpdates">Show Updates</button>
<button @click="hideUpdates">Hide Updates</button>
</div>
<ChangebotPanel ref="panelRef" mode="modal" />
</ChangebotProvider>
</template>
Composition API Example
<script setup>
import { ref, onMounted } from 'vue';
import {
ChangebotProvider,
ChangebotPanel
} from '@changebot/widgets-vue';
const panelRef = ref(null);
const isOpen = ref(false);
const togglePanel = async () => {
if (isOpen.value) {
await panelRef.value?.close();
} else {
await panelRef.value?.open();
}
isOpen.value = !isOpen.value;
};
// Auto-open on mount
onMounted(async () => {
await panelRef.value?.open();
isOpen.value = true;
});
</script>
<template>
<ChangebotProvider slug="acme-corp">
<button @click="togglePanel">
{{ isOpen ? 'Close' : 'Open' }} Updates
</button>
<ChangebotPanel
ref="panelRef"
mode="drawer-right"
theme="nord"
/>
</ChangebotProvider>
</template>
TypeScript Support
This package includes TypeScript definitions out of the box. All components are fully typed.
<script setup lang="ts">
import { ref } from 'vue';
import type { HTMLChangebotPanelElement } from '@changebot/widgets-vue';
const panelRef = ref<HTMLChangebotPanelElement | null>(null);
</script>
License
Apache-2.0
Links
Version History
| Version | Released | Vue | License |
|---|---|---|---|
| 0.5.0 | ^3.4.38 | Apache-2.0 | |
| 0.4.1 | ^3.0.0 | Apache-2.0 | |
| 0.4.0 | ^3.0.0 | Apache-2.0 | |
| 0.3.0 | ^3.0.0 | Apache-2.0 | |
| 0.2.3 | ^3.0.0 | Apache-2.0 | |
| 0.2.2 | ^3.0.0 | Apache-2.0 | |
| 0.2.1 | ^3.0.0 | Apache-2.0 | |
| 0.2.0 | ^3.0.0 | Apache-2.0 | |
| 0.1.22 | ^3.0.0 | Apache-2.0 | |
| 0.1.21 | ^3.0.0 | Apache-2.0 | |
| 0.1.20 | ^3.0.0 | Apache-2.0 | |
| 0.1.19 | ^3.0.0 | Apache-2.0 | |
| 0.1.18 | ^3.0.0 | Apache-2.0 | |
| 0.1.17 | ^3.0.0 | Apache-2.0 | |
| 0.1.16 | ^3.0.0 | Apache-2.0 | |
| 0.1.14 | ^3.0.0 | Apache-2.0 | |
| 0.1.13 | ^3.0.0 | Apache-2.0 | |
| 0.1.12 | ^3.0.0 | Apache-2.0 | |
| 0.1.11 | ^3.0.0 | Apache-2.0 | |
| 0.1.9 | ^3.0.0 | Apache-2.0 | |
| 0.1.8 | ^3.0.0 | Apache-2.0 | |
| 0.1.1 | ^3.0.0 | Apache-2.0 | |
| 0.1.0 | ^3.0.0 | Apache-2.0 | |
| 0.0.9 | ^3.0.0 | Apache-2.0 | |
| 0.0.8 | ^3.0.0 | Apache-2.0 | |
| 0.0.7 | ^3.0.0 | Apache-2.0 | |
| 0.0.6 | ^3.0.0 | Apache-2.0 | |
| 0.0.4 | ^3.0.0 | Apache-2.0 | |
| 0.0.3 | ^3.0.0 | Apache-2.0 | |
| 0.0.2 | ^3.0.0 | Apache-2.0 |