A lightweight Vue 3 component for displaying patch notes and update notifications to your users.
Demo β’ Documentation β’ GitHub
OpenPatch is a modern, lightweight patch notes widget that integrates easily into any web application. It automatically displays version notes to users only when a new version is released, storing the last seen version in localStorage.
- Dual mode: Use as a Vue component or standalone widget
- Fully customizable: CSS custom properties support
- Smart persistence: Remembers which updates users have seen
- Easy integration: Drop-in script or npm package
- TypeScript support: Full type definitions included
- Lightweight: Minimal bundle size with Tailwind CSS
- Responsive: Mobile-friendly design
- Accessible: ARIA standards compliant
- JSON configuration: Update patch notes without redeploying
npm install open-patch<link rel="stylesheet" href="https://williamloree.github.io/OpenPatch/open-patch.css">
<script src="https://williamloree.github.io/OpenPatch/openpatch.es.js" type="module"></script># Clone the repository
git clone https://github.com/williamloree/OpenPatch.git
cd OpenPatch
# Install dependencies
npm install
# Start development server
npm run dev<template>
<div>
<button @click="show">Show Updates</button>
<OpenPatch
project-id="my-app"
version="1.2.0"
:patchnotes="patchnotes"
title="What's New"
close-button-text="Got it!"
@close="handleClose"
@shown="handleShown"
/>
</div>
</template>
<script setup lang="ts">
import { OpenPatch, type PatchNotes } from 'open-patch'
import 'open-patch/style.css'
const patchnotes: PatchNotes = {
title: "Version 1.2.0",
sections: [
{
title: "New Features",
items: [
"Dark mode support",
"Export to PDF"
]
},
{
title: "Bug Fixes",
items: [
"Fixed login issue"
]
}
]
}
const handleClose = () => console.log('Patch notes closed')
const handleShown = () => console.log('Patch notes shown')
</script><script setup lang="ts">
import { useOpenPatch } from 'open-patch'
const { show, hide, reset } = useOpenPatch({
projectId: 'my-app',
version: '1.2.0',
patchnotes: {
title: "What's New",
sections: [
{
title: "Features",
items: ["New dashboard", "Export functionality"]
}
]
}
})
// Show the modal
show()
// Hide it programmatically
hide()
// Reset and show again
reset()
</script>Update your patch notes without redeploying your application!
The new architecture separates concerns:
- JSON file: Contains only
versionandpatchnotes(minimal viable configuration) - window.Settings: Contains
projectId,options, andcsscustomization
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://williamloree.github.io/OpenPatch/open-patch.css">
</head>
<body>
<h1>My Website</h1>
<script>
// Configure URL to fetch version and patchnotes
window.OpenPatchConfig = {
jsonUrl: '/patchnotes.json'
}
// Configure local options (projectId + options + css)
window.Settings = {
projectId: "my-app",
options: {
closeButtonText: "Got it!",
forceShow: false
},
css: {
primaryColor: "#4CAF50"
}
}
</script>
<script src="https://williamloree.github.io/OpenPatch/openpatch.es.js" type="module"></script>
</body>
</html>patchnotes.json (Minimal Configuration):
{
"version": "1.2.0",
"patchnotes": {
"title": "What's New",
"sections": [
{
"title": "Features",
"items": ["New dashboard", "Notifications"]
}
]
}
}Benefits of this architecture:
- Update patch notes without code deployment: Change only the JSON file
- CSS and options stay in HTML: No need to redeploy styling changes separately
- Separation of concerns: Content (JSON) vs. Configuration (HTML)
- Smaller JSON files: Only version and patch notes
- Automatic fallback: Uses
window.Settingsif JSON fails
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://williamloree.github.io/OpenPatch/open-patch.css">
</head>
<body>
<h1>My Website</h1>
<script>
window.Settings = {
projectId: "my-app",
version: "1.2.0",
patchnotes: {
title: "What's New",
sections: [
{
title: "Features",
items: ["New dashboard", "Export functionality"]
},
{
title: "Bug Fixes",
items: ["Fixed login issue"]
}
]
},
options: {
closeButtonText: "Got it!",
forceShow: false
},
css: {
primaryColor: "#4CAF50",
backgroundColor: "#f9f9f9",
textColor: "#333333",
buttonBackgroundColor: "#4CAF50",
buttonTextColor: "#ffffff",
borderColor: "#e0e0e0",
accentColor: "#81C784"
}
}
</script>
<script src="https://williamloree.github.io/OpenPatch/openpatch.es.js" type="module"></script>
</body>
</html>| Prop | Type | Required | Description |
|---|---|---|---|
projectId |
string |
β | Unique identifier for your project |
version |
string |
β | Current version number |
patchnotes |
PatchNotes |
β | Patch notes content |
title |
string |
β | Modal title (default: from patchnotes) |
closeButtonText |
string |
β | Close button text (default: "Compris !") |
forceShow |
boolean |
β | Always show modal (default: false) |
cssCustomization |
CSSCustomization |
β | CSS custom properties |
@close- Emitted when modal is closed@shown- Emitted when modal is displayed
// Show the modal
window.OpenPatch.show()
// Hide the modal
window.OpenPatch.hide()
// Reset (clear storage and show again)
window.OpenPatch.reset()OpenPatch offers a complete customization system via the css object in configuration.
| Property | Type | Default | Description |
|---|---|---|---|
primaryColor |
string |
#0f172a |
Primary color (titles, borders on hover) |
backgroundColor |
string |
#ffffff |
Modal background color |
textColor |
string |
#334155 |
Main text color |
buttonBackgroundColor |
string |
#0f172a |
Button background color |
buttonTextColor |
string |
#ffffff |
Button text color |
borderColor |
string |
#e2e8f0 |
Border color |
accentColor |
string |
#cbd5e1 |
Accent color (bullets, item borders) |
css: {
primaryColor: "#4CAF50",
backgroundColor: "#f9f9f9",
textColor: "#333333",
buttonBackgroundColor: "#4CAF50",
buttonTextColor: "#ffffff",
borderColor: "#e0e0e0",
accentColor: "#81C784"
}css: {
primaryColor: "#1976D2",
backgroundColor: "#ffffff",
textColor: "#263238",
buttonBackgroundColor: "#1976D2",
buttonTextColor: "#ffffff",
borderColor: "#BBDEFB",
accentColor: "#64B5F6"
}css: {
primaryColor: "#BB86FC",
backgroundColor: "#1E1E1E",
textColor: "#E1E1E1",
buttonBackgroundColor: "#BB86FC",
buttonTextColor: "#000000",
borderColor: "#2C2C2C",
accentColor: "#03DAC6"
}css: {
primaryColor: "#FF6B35",
backgroundColor: "#FFF8F3",
textColor: "#2D3142",
buttonBackgroundColor: "#FF6B35",
buttonTextColor: "#ffffff",
borderColor: "#FFE5D9",
accentColor: "#FFB997"
}interface PatchNotesConfig {
title: string
sections: Array<{
title: string
items: string[]
}>
}const patchnotes: PatchNotesConfig = {
title: "Version 2.0.0 - Major Redesign",
sections: [
{
title: "π New Features",
items: [
"Redesigned user interface",
"Real-time collaborative mode",
"Complete REST API integration"
]
},
{
title: "β‘ Improvements",
items: [
"3x faster loading performance",
"40% reduction in bundle size",
"Offline PWA support"
]
},
{
title: "π Bug Fixes",
items: [
"Fixed crash on iOS Safari",
"Fixed synchronization bug",
"Resolved CORS issues"
]
}
]
}Full TypeScript definitions are included:
import type {
PatchNotesConfig,
PatchNoteSection,
WindowSettings,
CSSCustomization,
WidgetOptions,
OpenPatchConfig,
JSONConfig
} from 'open-patch'
// Aliases for compatibility
import type { PatchNotesConfig as PatchNotes } from 'open-patch'
import type { WindowSettings as OpenPatchSettings } from 'open-patch'Use semver format:
1.2.3
β β β
β β ββ Patch (bug fixes)
β ββββ Minor (new features)
ββββββ Major (breaking changes)
Storage key format: openpatch_last_seen_{projectId}
// Example of stored data
localStorage.getItem('openpatch_last_seen_my-app')
// β "1.2.0"# Development
npm run dev # Start development server
# Build
npm run build # Complete build (lib + standalone + types)
npm run build:lib # Build Vue library
npm run build:standalone # Build standalone for CDN
# Preview
npm run preview # Preview build
npm run serve:example # Serve example pageOpenPatch/
βββ src/
β βββ components/
β β βββ OpenPatch.vue # Main component
β βββ composables/
β β βββ useOpenPatch.ts # Composable
β βββ types/
β β βββ settings.ts # TypeScript definitions
β βββ utils/
β β βββ configLoader.ts # Config loader utility
β βββ index.ts # Library entry point
β βββ standalone.ts # Standalone entry point
β βββ App.vue # Demo app
β βββ main.ts # Vue entry point
βββ dist/ # Build output
βββ public/ # Static assets
βββ README.md # This file
Q: How to reset version history?
A: Use window.OpenPatch.reset() or delete the localStorage key
Q: Does the widget work without Vue? A: Yes! Use standalone mode
Q: Can I fully customize the design?
A: Yes, via the css configuration object
Q: How to manage multiple projects?
A: Use different projectId for each project
Q: Is the widget accessible (ARIA)? A: Yes, accessibility standards are respected
# Complete build
npm run buildGenerated files in dist/:
index.es.js- ES Module for Vue projects (8.2 kB)openpatch.es.js- Standalone ES Module with Vue (123 kB)openpatch.umd.js- Standalone UMD with Vue (77 kB)open-patch.css- Compiled Tailwind styles (21 kB)index.d.ts- TypeScript definitions
# Login to npm
npm login
# Publish package
npm publishThe project is configured to deploy automatically via GitHub Actions. Each push to main triggers a build and deployment.
Demo URL: https://williamloree.github.io/OpenPatch/
- β¨ Complete CSS customization system
- β¨ Multi-section support
- β¨ JSON configuration mode
- β‘ Performance improvements
- π¨ Complete Tailwind rewrite
- π¦ NPM package ready
- π§ Dual mode (Vue + Standalone)
- Chrome/Edge (latest)
- Firefox (latest)
- Safari (latest)
- Modern browsers with ES modules support
Contributions are welcome! Feel free to open an issue or submit a pull request.
MIT License - see the LICENSE file for details.
- Repository: github.com/williamloree/OpenPatch
- Issues: github.com/williamloree/OpenPatch/issues
- Demo: williamloree.github.io/OpenPatch
- NPM: npmjs.com/package/open-patch
Made with β€οΈ by williamloree
If this project helps you, consider giving it a β!