@castlenine/vite-plugin-remove-attribute
| Install | |
|---|---|
npm install @castlenine/vite-plugin-remove-attribute |
|
| Latest Version: | 2.1.0 |
| Vue: | 3 |
| License: | MIT |
| Last Updated: | Sep 27, 2026 |
| Links: | GitHub · npm |
@castlenine/vite-plugin-remove-attribute
Vite plugin that removes specified attributes, such as 'data-testid' used in testing. Options cover file extensions, attributes, and folders and files to ignore.
Table of Contents
- Disclaimer
- Features
- Requirements
- Installation
- Usage
- Examples
- Changelog
- Acknowledgment
- License
Disclaimer
Tested against real vite build runs with Svelte / SvelteKit, Vue.js, React, Preact, Solid, Astro, Lit (html templates in .ts), entry HTML and Angular through Analog with fastCompile. Qwik is verified on the transform only, because Qwik 1.20 does not yet support Vite 8. Please open an issue if you run into problems with these or other frameworks.
Features
- Removes an attribute in every form it is written in: quoted, expression (
={…}), unquoted, bare, and behind a Vue:/v-bind:prefix with modifiers. - Processes markup and JSX files out of the box (
DEFAULT_EXTENSIONS); plain script files are opt-in. - Ships frozen extension presets (
SVELTE_EXTENSIONS,VUE_EXTENSIONS,SCRIPT_EXTENSIONS, …) that you compose instead of listing extensions by hand. - Handles
${…}placeholders inside quoted values, so a Lit-style value with nested quotes is removed whole. - Edits only real opening tags.
- Leaves an attribute it cannot parse in place and emits a build warning.
- Skips the folders and files you configure, on top of a built-in ignore list.
- Emits a sourcemap for each changed file when sourcemaps are enabled.
Requirements
| Requirement | Version |
|---|---|
| Node.js | >=18.0.0 |
| Vite | >=2.0.0 (peer dependency) |
Installation
Use your package manager to install it as a development dependency:
pnpm add -D @castlenine/vite-plugin-remove-attribute
# or
npm i -D @castlenine/vite-plugin-remove-attribute
# or
yarn add -D @castlenine/vite-plugin-remove-attribute
Usage
Quick start
List removeAttribute() first in plugins:
import { defineConfig } from 'vite';
import { sveltekit } from '@sveltejs/kit/vite';
import removeAttribute from '@castlenine/vite-plugin-remove-attribute';
export default defineConfig({
plugins: [removeAttribute({ attributes: ['data-testid'] }), sveltekit()],
});
This removes data-testid from every markup and JSX file (DEFAULT_EXTENSIONS).
Most projects only want the attributes gone from production builds. Enable the plugin in production mode only:
export default defineConfig(({ mode }) => ({
plugins: [mode === 'production' ? removeAttribute({ attributes: ['data-testid'] }) : null, sveltekit()],
}));
That keeps test IDs in dev and in Vitest (which runs with mode: 'test'), where Testing Library's getByTestId needs them. Vite ignores falsy entries in plugins, so mode === 'production' && removeAttribute(...) is equivalent to the ternary.
Upgrading from 2.0.x
Existing configs keep working unchanged. One option was added (removeInStrings), extensions became optional, and the option types were widened to readonly string[]. The output can differ, though:
- Markup inside JS strings is no longer stripped. Set
removeInStrings: trueto get the old behavior back. - The built-in ignore list changed (see
ignoreDefaults). Tokens other thannode_modulesand.gitnow match only as the first folder under the Vite root; add nested folders toignoreFoldersif you still want them skipped. The list gained.output,.nitro,.data,out,.react-router,.astro,.solid,.vinxi,.tanstack,.angular,.vercel,.netlifyand.wrangler, and dropped.remix. Workspace packages resolved outside the Vite root (../other/dist/…) are no longer skipped by default. - A JS config that omits
extensionsnow processesDEFAULT_EXTENSIONS. Before, it processed nothing. - The build can now log warnings for values the plugin cannot parse and for option lists that end up empty. These never fail the build.
See the CHANGELOG.md for the full list.
Plugin order
The plugin declares enforce: 'pre'. Vite sorts plugins by enforce (pre, then normal, then post) and keeps array order within pre. So the position in plugins only matters next to another pre plugin that compiles markup. Listing removeAttribute() first works for every framework except Svelte with a markup preprocessor, and it is the recommended setup.
| Framework | Order |
|---|---|
Vue (@vitejs/plugin-vue) |
Any order: it has no pre plugin |
| Lit, entry HTML | Any order: no framework plugin is involved |
React (@vitejs/plugin-react 5.x, 6.x default; @vitejs/plugin-react-swc default) |
Any order: JSX is compiled by Vite core (oxc / esbuild) or in the normal phase |
React with a pre compile step |
List removeAttribute() first. This covers plugin-react 6's compiler option (React Compiler), plugin-react-swc with SWC plugins or useAtYourOwnRisk_mutateSwcOptions in build, and a Babel pre plugin (such as @rolldown/plugin-babel) that reprints the code |
Svelte / SvelteKit (vite-plugin-svelte 7) |
Any order: compilation is post. With a markup preprocessor such as Pug, list removeAttribute() after sveltekit() / svelte() so it reads the preprocessed markup |
Solid (vite-plugin-solid), Preact (@preact/preset-vite) |
Both orders work (integration-tested). When listed after them, the plugin reads their compiled output |
| Astro | Any order: astro:build is pre and registered before user plugins, so Astro always compiles first (see Astro) |
| Angular through Analog | Must come before angular() (see Angular through Analog) |
Qwik (qwikVite(), 1.x and v2 beta) |
List removeAttribute() before qwikVite(), which compiles JSX in a pre transform. This is the only tested order |
Options
Only attributes is required.
| Option | Type | Default | Description |
|---|---|---|---|
extensions |
readonly string[] |
DEFAULT_EXTENSIONS |
File extensions to process, without the dot |
attributes |
readonly string[] |
— | Attribute names to remove (e.g. ['data-testid']) |
ignoreFolders |
readonly string[] |
[] |
Folders to skip (e.g. ['src/tests']) |
ignoreFiles |
readonly string[] |
[] |
Files to skip (e.g. ['Header.svelte', 'src/lib/Modal.svelte']) |
ignoreDefaults |
boolean |
true |
Also apply the built-in ignore list |
removeInStrings |
boolean |
false |
Also remove attributes from markup inside quoted JS strings |
In attributes and extensions, entries that are not strings, or are empty or whitespace-only, are dropped. The rest are trimmed and de-duplicated. If either list ends up empty, the plugin logs one [remove-attributes] warning per plugin instance through Vite's logger, naming the rejected entries. The build does not fail.
attributes
The attribute names to remove, matched case-insensitively. Longer names such as data-testid-extra are left alone. With no valid name left after cleaning, the plugin does nothing.
Only attributes inside real opening tags are removed, so a name that is also a JavaScript identifier (title, id, …) leaves script code such as let title = 'Home' untouched.
removeAttribute({ attributes: ['data-testid', 'data-cy'] });
extensions
The file extensions to process, written without the leading dot.
When extensions is omitted, DEFAULT_EXTENSIONS applies: markup and JSX only (jsx, tsx, svelte, vue, astro, html, htm). Plain script files (js, mjs, cjs, ts, mts, cts) are processed only if you add JAVASCRIPT_EXTENSIONS, TYPESCRIPT_EXTENSIONS or SCRIPT_EXTENSIONS.
The package exports nine frozen preset arrays. Options.extensions is typed readonly string[], so you can pass a preset directly (extensions: DEFAULT_EXTENSIONS) or spread several into a new array. Mutating a preset throws.
| Constant | Extensions | Typical use |
|---|---|---|
JAVASCRIPT_EXTENSIONS |
js, mjs, cjs |
Opt-in: plain JavaScript; also Lit |
TYPESCRIPT_EXTENSIONS |
ts, mts, cts |
Opt-in: plain TypeScript; also Lit and Angular |
JSX_EXTENSIONS |
jsx, tsx |
React, Preact, Solid, Qwik, Vue JSX (none has an extension of its own) |
SCRIPT_EXTENSIONS |
Union of the three above | Opt-in: the 8 extensions Vite treats as script |
SVELTE_EXTENSIONS |
svelte |
Svelte / SvelteKit (.svelte.js / .svelte.ts rune modules fall under the script presets) |
VUE_EXTENSIONS |
vue |
Vue single-file components |
ASTRO_EXTENSIONS |
astro |
Astro components |
HTML_EXTENSIONS |
html, htm |
Entry HTML files (vite build only, see Good to know) |
DEFAULT_EXTENSIONS |
Union of JSX_, SVELTE_, VUE_, ASTRO_ and HTML_EXTENSIONS |
Used when extensions is omitted |
Compose presets to cover exactly the file kinds a project uses:
import removeAttribute, { JSX_EXTENSIONS, SVELTE_EXTENSIONS } from '@castlenine/vite-plugin-remove-attribute';
removeAttribute({ extensions: [...JSX_EXTENSIONS, ...SVELTE_EXTENSIONS], attributes: ['data-testid'] });
Extend the default set with a custom extension:
import removeAttribute, { DEFAULT_EXTENSIONS } from '@castlenine/vite-plugin-remove-attribute';
removeAttribute({ extensions: [...DEFAULT_EXTENSIONS, 'svx'], attributes: ['data-testid'] });
Or opt script files in for a Lit or Angular inline template:
import removeAttribute, { DEFAULT_EXTENSIONS, TYPESCRIPT_EXTENSIONS } from '@castlenine/vite-plugin-remove-attribute';
removeAttribute({ extensions: [...DEFAULT_EXTENSIONS, ...TYPESCRIPT_EXTENSIONS], attributes: ['data-testid'] });
Script extensions are opt-in because they add scan time for little gain:
- In a plain script file, the plugin only removes attributes written as markup, such as inside a Lit
htmltemplate or an Angular inlinetemplate:. Other JS strings are edited only withremoveInStrings, and object-style props likeh('div', { 'data-testid': 'x' })orcreateElementprops are never matched. - Adding a script preset means every script module in the project gets scanned.
A plain array of strings without any preset is still valid (see the Vue.js example).
ignoreFolders and ignoreFiles
Folders and files the plugin skips. Each entry is a token written with / separators and matched against the module path relative to the Vite root:
\is normalized to/, and a leading./,../or/is dropped, not resolved:'src\\tests'issrc/tests,'../shared'isshared.- Matching happens on path-segment boundaries.
buildmatchesbuild/app.jsbut notbuildhome/app.js, andsrc/testsmatchessrc/tests/a.sveltebut notsrc/tests-e2e/a.svelte. - A
*matches any characters within one segment (*.stories.svelte,.env.*). - Your tokens are never root-anchored: they match a run of whole segments at any depth.
src/testsskips bothsrc/tests/a.svelteandlib/src/tests/a.svelte, and'../shared'matchesshared/a.tsandsrc/shared/a.tsbut notsharedx/. - A module id's
?queryand#hashsuffixes are ignored (a#followed by/is part of a folder name). - Each build resolves tokens against its own root, so concurrent builds sharing one plugin instance stay independent.
removeAttribute({ attributes: ['data-testid'], ignoreFolders: ['src/tests'] });
removeAttribute({ attributes: ['data-testid'], ignoreFiles: ['Header.svelte', 'src/lib/Modal.svelte'] });
ignoreDefaults
Whether the built-in ignore list applies on top of ignoreFolders / ignoreFiles (default true).
Only node_modules and .git match at any depth. Every other built-in token matches only as the first path segment under the Vite root. So build/App.svelte is skipped, while src/routes/public/+page.svelte, src/lib/build/Step.svelte and src/e2e/Foo.svelte are processed like any other source file.
| Framework / tool | Ignored tokens |
|---|---|
| IDE / OS | .idea, .vscode, .DS_Store, Thumbs.db |
| Environment / logs | .env, .env.*, logs, *.log |
| Svelte / SvelteKit | public, build, .svelte-kit |
| Vue.js / Nuxt | .nuxt |
| Nitro (Nuxt, SolidStart, TanStack Start) | .output, .nitro, .data |
| React.js / Next.js | .next, out |
| React Router | .react-router |
| Astro | .astro |
| SolidStart | .solid, .vinxi |
| TanStack Start | .tanstack |
| Angular | .angular, e2e, angular.json, browserslist |
| Deploy adapters | .vercel, .netlify, .wrangler |
| Build output / cache | dist, .cache |
Set ignoreDefaults: false to keep only your own tokens. Files under public/ or build/ are then processed too:
removeAttribute({
extensions: ['svelte'],
attributes: ['data-testid'],
ignoreDefaults: false,
ignoreFolders: ['node_modules'],
});
removeInStrings
Whether markup inside plain quoted JS strings is edited too (default false; only a literal true enables it).
When enabled, a single- or double-quoted string in script code that holds well-formed markup is read as markup. That covers <script> blocks, whole script/TS modules, Astro frontmatter, Svelte {…} / {@html …} expressions and Vue {{ }}:
removeAttribute({ attributes: ['data-testid'], removeInStrings: true });
// Before
el.innerHTML = '<div data-testid="panel"></div>';
// After
el.innerHTML = '<div></div>';
Svelte {@html '<em data-testid="note">Note</em>'} becomes {@html '<em>Note</em>'} the same way.
Even when enabled, these stay byte-identical:
- strings with no
<; - strings containing a backslash (such as escaped quotes,
"<div data-testid=\"x\">") or a line break; - strings whose tag or quoted value is not closed inside the string, such as concatenation (
'<div data-testid="' + id + '">') or'<div data-testid'; - attribute values inside JSX tags.
Every plain quoted string holding closed markup is edited, not only strings used as markup (innerHTML and the like). That includes object keys ({ '<b data-testid="x"></b>': 1 } becomes { '<b></b>': 1 }), TypeScript string-literal types, import specifiers and every string of a compiled Astro module. Code that compares a string against literal HTML (outerHTML === '<div data-testid="x"></div>') sees the changed value.
In .svelte files, a value that opens a mustache inside a string ('<p data-testid="{">') is removed within the string when it can be bounded there. Otherwise it is left in place with the "left N attribute(s) in place" warning.
Template literals and Angular inline template: strings are read as markup without this option.
How matching works
Forms that are removed
- Quoted:
data-testid="a". - Expression:
data-testid={value}, including template literals with nested${…}. - Unquoted:
data-testid=foo, alsodata-testid = fooand<input data-testid=foo/>. The value may continue through a balanced{…}, such asdata-testid=a{b}, or Solid's compiled$\{…}form when the plugin runs aftervite-plugin-solid. - Tagged-template placeholder:
data-testid=${id}, alsodata-testid=${a}-${b}, as used in Lithtmltemplates. - Bare:
<input data-testid />. - With a Vue binding prefix:
:data-testid,v-bind:data-testid. Modifiers go with the prefix (:data-testid.attr="x",v-bind:data-testid.camel.prop="x"). - Right after a closing
",'or}with no whitespace (class="x"data-testid="y", as minifiers emit it). Two removed attributes written back-to-back are both taken out.
Inside an expression value (={…}):
//and/* */comments and regular expression literals are read past, so a brace inside them does not end the value.- Nested JSX elements (tags, their attribute strings, text content and fragments) are read as markup. An apostrophe, a
}or a<inside them does not end the scan early.
Inside a quoted value:
- In
.sveltefiles, a value holding a mustache with nested quotes (data-testid="{ok ? "a" : "b"}", which also covers${…}) is read as an expression and removed whole. - In every other file type (
js/ts,jsx/tsx,.vue,.astro,.html), the value steps over${…}placeholders. A tagged-template value with nested quotes or nested template literals (data-testid="${ok ? "a" : `b-${id}`}") is removed whole, including a Lit-style template inside a<script>block of a.vue,.astroor.htmlfile. - An escaped
\${opens no placeholder. A placeholder that does not balance falls back to reading the value up to its first closing quote.
When a value cannot be parsed
The attribute stays in place and the plugin emits a build warning (one per module, pointing at the first occurrence). This happens with:
- an unbalanced
={; - an unbalanced
{inside an unquoted value (data-testid=a{b); - an element opened inside the value that is never closed, or is closed by a differently named tag. An old-style cast (
={<Foo>bar}) counts, since it reads as an unclosed element.
A file with several unbalanced ={ expressions does not parse. To keep the transform linear, the plugin stops scanning expression values for the rest of that file, leaves those attributes untouched and warns about them. Quoted values holding a mustache or a ${…} placeholder are left in place and warned about too, rather than cut at an inner quote.
Good to know
- Entry HTML (
index.html) only passes through the plugin duringvite build. The dev server serves it without callingtransform, so the attributes stay in dev. - Attributes are removed only inside real opening tags. Text nodes,
<pre>content, HTML/JS/template comments, JS strings, regular expression literals, JSX text, template text outside tags,<style>, JSON / importmap /srcscript bodies, Markdown fences and non-Astro front matter stay byte-identical.<script>/<style>content inside template-literal markup (Lit, Angular inline templates, compiled Astro) is read as raw text. - Style sub-requests (
?vue&type=style…, Sveltetype=style,html-proxy&inline-css, CSS-language queries) are skipped entirely. - In
.ts/.mts/.ctsfiles, only markup inside template literals is read, since TypeScript has no JSX there. Raw markup outside a template literal and non-HTML template syntaxes such as Pug are not touched. - The "left N attribute(s) in place" warning fires once per module per plugin instance. A client + SSR build warns once, and watch mode does not repeat it on rebuild.
Framework notes
Astro
Astro compiles .astro files before the plugin sees them (see Plugin order), so the plugin works on compiled modules; it detects this per Vite environment. It removes static and bare attributes, expression values (data-testid={id}, compiled to ${$$addAttribute(id, "data-testid")} and matched case-insensitively), shorthand {data-testid}, and configured props on components, custom elements and <Fragment>. Any other compiled shape is left untouched.
Attributes passed through a spread ({...props}) and inline-script text survive. Names inside set:html strings survive by default; with removeInStrings they are removed (compiled $$unescapeHTML("<span data-testid='x'>raw</span>") becomes <span>raw</span>). Registering the plugin through an integration's astro:config:setup hook behaves the same way.
Angular through Analog
With Analog (@analogjs/vite-plugin-angular), list removeAttribute() before angular() and enable fastCompile. With Analog's default AOT compiler nothing is removed: it builds its TypeScript program from the files on disk in buildStart, before any Vite transform runs.
An inline template: (the value of a template key after { or ,) is read as markup when written as a template literal or a single/double-quoted string, even without removeInStrings. A quoted string is left as a plain string when it holds no <, contains a backslash or a line break, reaches the region end, or has a tag, quoted value, comment or raw-text element (such as <textarea> or <script>) that does not close inside the string. Ternary values and quoted 'template': keys are not recognized. External templateUrl templates are not stripped (see Known limitations).
Under fastCompile, a plain attribute in an inline template (data-testid="…", including a value with ${…} placeholders) is removed. A property binding ([attr.data-testid]="…") is left alone and still sets the attribute at runtime. fastCompile skips Angular's template type-checking and compiles a quoted value containing ${…} to an empty string; both are Analog's own behavior, independent of this plugin.
import angular from '@analogjs/vite-plugin-angular';
import removeAttribute, { DEFAULT_EXTENSIONS, TYPESCRIPT_EXTENSIONS } from '@castlenine/vite-plugin-remove-attribute';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [
removeAttribute({ extensions: [...DEFAULT_EXTENSIONS, ...TYPESCRIPT_EXTENSIONS], attributes: ['data-testid'] }),
angular({ fastCompile: true }),
],
});
Not supported
- The Markdown family (
md,svx,mdx) has no preset. You can add an extension toextensionsmanually; fenced code samples are left untouched, but inline code spans and 4-space indented code blocks are still edited. - Astro re-reads
.mdcontent from disk rather than passing it through Vite's module graph, so the plugin has no effect on Astro Markdown either way. - Marko (
.marko), Riot (.riot) and Ripple (.tsrx) are unverified with apre-enforced transform. They have no preset; add their extension manually and at your own risk. - Imba, Civet, CoffeeScript, ReScript, Elm and Gleam are separate languages, not HTML/JSX markup, and must never be added to
extensions.
Known limitations
- Angular
templateUrl. External.htmltemplates are not stripped: Angular reads them from disk, so they never pass through Vite'stransform. - Files that do not parse. Several unbalanced
={expressions stop expression scanning for the rest of the file (see When a value cannot be parsed).
Scanner edge cases
/and<inside={…}. Whether a/starts a regular expression or divides, and whether a<opens an element or compares, is decided from the previous token (punctuation, a keyword such asreturn/typeof, or a TypeScript non-null!). Misreads remain possible but rare.- Stray
{in Svelte. A quoted value with a stray unclosed{(data-testid="{" class="}c", which is not valid Svelte) can take the next attribute with it, with no warning. - Literal
${outside Svelte. It is read as a placeholder, sodata-testid="${" class="}"also removesclass, with no warning. In.astrofiles, Astro escapes it as\${first, soclasssurvives in a real build. - Fallback to the plain read. A literal
${(or Svelte{) whose continuation stops reading as JavaScript, such as a string running into a line break or followed directly by a word, number, string or{, falls back to the plain read even if a component brace follows later. - Undetectable markup. Markup that reads as JavaScript token for token up to a
}cannot be told apart from a template literal:<b data-testid="${">x</b><i title="}">y</i>becomes<b>y</i>. <textarea>/<title>content. Tags written inside their content are still edited.
Sourcemaps
The plugin builds sourcemaps itself, with no runtime dependency, using word-boundary segments (the magic-string hires: 'boundary' equivalent), so code keeps mapping to the original lines and columns even when an attribute sat on its own line. The dev server always gets a map. During vite build, a map is produced only when the resolved build.sourcemap is on (on Vite 6+ the per-environment setting wins). An html-proxy inline-script map is named after the proxy id and carries sourcesContent.
Examples
SvelteKit example 1: Removing 'data-testid' attributes from .svelte files
Removes data-testid from all .svelte files, in the production build only.
import { defineConfig } from 'vite';
import { sveltekit } from '@sveltejs/kit/vite';
import removeAttribute, { SVELTE_EXTENSIONS } from '@castlenine/vite-plugin-remove-attribute';
export default defineConfig(({ mode }) => ({
plugins: [
mode === 'production'
? removeAttribute({
extensions: [...SVELTE_EXTENSIONS],
attributes: ['data-testid'],
})
: null,
sveltekit(), // Either order works: vite-plugin-svelte compiles in the post phase
],
}));
SvelteKit example 2: Ignoring specific folders and files
Removes data-testid and data-id from all .svelte, .ts and .js files in every build, except files in src/tests and src/utilities and the files Header.svelte, src/components/Modal.svelte and src/layouts/LayoutAuth.svelte.
import { defineConfig } from 'vite';
import { sveltekit } from '@sveltejs/kit/vite';
import removeAttribute, { JAVASCRIPT_EXTENSIONS, SVELTE_EXTENSIONS, TYPESCRIPT_EXTENSIONS } from '@castlenine/vite-plugin-remove-attribute';
export default defineConfig({
plugins: [
removeAttribute({
extensions: [...SVELTE_EXTENSIONS, ...TYPESCRIPT_EXTENSIONS, ...JAVASCRIPT_EXTENSIONS],
attributes: ['data-testid', 'data-id'],
ignoreFolders: ['src/tests', 'src/utilities'],
ignoreFiles: ['Header.svelte', 'src/components/Modal.svelte', 'src/layouts/LayoutAuth.svelte'],
}),
sveltekit(), // Either order works: vite-plugin-svelte compiles in the post phase
],
});
Vue.js example: Removing 'data-testid' attributes from .vue files
Removes data-testid from all .vue files, in the production build only.
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import removeAttribute from '@castlenine/vite-plugin-remove-attribute';
export default defineConfig(({ mode }) => ({
plugins: [
mode === 'production'
? removeAttribute({
extensions: ['vue'],
attributes: ['data-testid'],
})
: null,
vue(), // Any order works: plugin-vue has no pre plugin
],
}));
CommonJS
The package also ships a CommonJS entry. require() returns the plugin function directly (.default works too), and every extension preset (SVELTE_EXTENSIONS, DEFAULT_EXTENSIONS, …) is a property of that function:
// vite.config.cjs
const { defineConfig } = require('vite');
const removeAttribute = require('@castlenine/vite-plugin-remove-attribute');
module.exports = defineConfig({
plugins: [
removeAttribute({
extensions: [...removeAttribute.SVELTE_EXTENSIONS],
attributes: ['data-testid'],
}),
],
});
Changelog
For more information, refer to the CHANGELOG.md.
Acknowledgment
This project is a fork of mustafadalga/remove-attr. See ACKNOWLEDGMENT.md for more details.
License
Related Packages
A Vite plugin that removes console calls from your production build and keeps th...
integrate zikojs elements within other ui framework like vue react solidjs svelt...
Version History
| Version | Released | Vue | License |
|---|---|---|---|
| 2.1.0 | ^3.5.43 | MIT | |
| 2.0.3 | MIT | ||
| 2.0.2 | MIT | ||
| 2.0.1 | MIT | ||
| 2.0.0 | MIT |