Migration v1 → v2
A guide for those already using ozi-ui v1 who want to move to v2.
The v2 principle: ozi-ui depends on no third-party library. Pure JavaScript — jQuery survives only in the integrations/ layer (compatibility shims).
Good news: most of your code does not break. The
data-ozi-*anddata-zld-*attributes, the public API (OZI.components.*/window.OziX) and thezld*aliases keep working. What actually changes is listed below.
1. Versions
Versioning is major +1 per plugin — not a single version for everything.
| Plugin | v1 | v2 |
|---|---|---|
ozi.js (index) |
1.0.7 | 2.0.0 (OZI.version) |
ozi-conf |
2.0.x | 3.0.0 |
ozi-loaddata |
4.x | 5.0.0 |
ozi-select |
5.x | 6.0.0 |
ozi-autocomplete · ozi-editor · ozi-auth · ozi-search · ozi-audio |
3.x | 4.0.0 |
ozi-editor-md |
1.x | 2.0.0 |
ozi-check · ozi-toggle |
2.x | 3.0.0 |
ozi-validate |
1.x | 2.1.0 |
ozi-actions · ozi-suggest |
1.x | 2.0.0 |
ozi-helpers |
1.0.x | 1.1.0 |
The Composer package publishes 2.0.0. v1 remains available under the v1-final tag.
composer require ozi-ui/core:^2.0
2. Zero jQuery — what to do
Before (v1): ozi.js shipped and used jQuery; many projects relied on the window.$ that "came along".
After (v2): the core does not use jQuery and does not load it at boot. It is still distributed at core/jquery-3.7.1.min.js for those who need it.
Action: if your app relied on the jQuery that came with ozi-ui, include it yourself:
<script src="https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js"></script>
3. The event contract — the most important change
In v1 events were dual-dispatch: $(el).trigger() (jQuery positional payload) and CustomEvent. In v2 it is CustomEvent only, with the payload in detail:
detail: { component: 'ozi-select', name: 'uf', value: 'SP', items: [...], source: 'user' }
// source: 'user' (user interaction) | 'api' (programmatic setValue)
Consuming ozi:change
// ❌ v1 — jQuery positional
$('[data-ozi-select="uf"]').on('ozi:change', function (e, items, instance, detail) {
console.log(detail.value);
});
// ✅ v2 — native CustomEvent
document.addEventListener('ozi:change', function (e) {
if (e.detail.component !== 'ozi-select') return;
console.log(e.detail.name, e.detail.value); // 'uf', 'SP'
});
<!-- ✅ v2 — Alpine -->
<div x-on:ozi:change="$wire.set('uf', $event.detail.value)"></div>
detail key changes
| v1 | v2 |
|---|---|
key |
name |
instance |
removed — use OZI.components.select.get(el) |
ozi-check: source (switch/group/item) |
level — source is now 'user'|'api' |
ozi-search |
value = query; keeps query/matched/total |
ozi-auth |
new in v2 — now emits CustomEvent (was jQuery-only) |
Every component now emits ozi:init (after initialization) and ozi:destroy.
Compatibility without rewriting (shims)
If you have consumers using the v1 positional format, enable the shim — it listens to the CustomEvent and re-emits it through jQuery in the old format. Nothing in your code has to change.
integrations/adapters/ozi-change-v1-compat.shim.js— positionalozi:changeintegrations/adapters/ozi-check-v1-events.shim.js—oziCheck:initFetched
The shims are temporary and require jQuery. Move to addEventListener when you can.
4. Discontinued: ozi-copy and ozi-paste
Both were removed in v2. The replacements are short Alpine or vanilla JS recipes — with no icon-font dependency.
<!-- ozi-copy replacement -->
<button type="button"
x-data="{ copied: false }"
@click="navigator.clipboard.writeText('ABC-123').then(() => { copied = true; setTimeout(() => copied = false, 1500) })">
<span x-text="copied ? '✓ copied' : 'Copy'"></span>
</button>
The v1 plugins remain available under the v1-final tag.
ozi-audiowas NOT discontinued — it stays in scope and was migrated (v4.0.0).
5. Livewire
The adapter gained a native mode that respects wire:model modifiers:
<!-- Mode A (preferred): native dispatch — respects .live/.debounce/.lazy -->
<div wire:ignore>
<div data-ozi-select="uf" data-ozi-livewire-native="#uf-hidden"></div>
</div>
<input id="uf-hidden" type="hidden" wire:model="uf">
<!-- Mode B (compat): component.set() -->
<div data-ozi-select="uf" data-ozi-livewire-model="uf"></div>
- Anti-loop: the adapter ignores
ozi:changewithsource: 'api'(a change coming from Livewire itself). - Re-init after morph: handled by
ozi-hooks— nothing to do. - LW3 × LW4 guard is automatic.
6. Themes
A theme is data: 4 files linked in the <head> (tokens.css, overrides.css, dark.css, classmap.js). The same JS build serves all three themes — you only change oziConf({ theme }).
<link rel="stylesheet" href="/plugins/ozi-ui/themes/tailwind/tokens.css">
<link rel="stylesheet" href="/plugins/ozi-ui/themes/tailwind/overrides.css"><!-- new in v2 -->
<link rel="stylesheet" href="/plugins/ozi-ui/themes/tailwind/dark.css">
<script>oziConf({ theme: 'tailwind' });</script>
New in v2: themes/tailwind/overrides.css, which did not exist in v1. For a custom theme, copy themes/_template/.
7. Legacy aliases
They keep working, with a console warning when core.log: true. They will be removed in a future version:
| v1 alias | Use in v2 |
|---|---|
window.oziCore |
window.OZI |
window.oziLoaddata |
window.oziLoadData |
window.OziFrameworks |
OZI.integrations |
window.zldActions(arr) |
OZI.modules.actions.run(arr) |
window.oziValidateContainer(c) |
OZI.modules.validate.container(c) |
zldParseBool / zldGenerateId / … |
OZI.helpers.* |
8. Migration checklist
- [ ] Include jQuery yourself if your app relied on the one bundled with ozi-ui (§2)
- [ ] Move
ozi:changeconsumers toaddEventListener+e.detail(§3) — or enable the shim - [ ] Replace
ozi-copy/ozi-pastewith the Alpine recipes (§4) - [ ] (Livewire) consider mode A (
data-ozi-livewire-native) to respectwire:model(§5) - [ ] (Tailwind) link the new
overrides.css(§6) - [ ] Remove usages of legacy aliases (§7)
- [ ] Run the app with
oziConf({ core: { log: true } })to see deprecation warnings
9. What does not change
data-ozi-*anddata-zld-*attributes (declarative markup)- Public API:
OZI.components.<name>andwindow.Ozi<Name> oziConf({...}),@oziScripts/@oziStyles(Blade),OZI.ready()ozi-loaddata: fetch, DOM target, collection, progress, actions — identical behavior