{"_id":"@adrii_/wizard-js","_rev":"16-2b372851948d6ef8378e2a217ea8d8d0","name":"@adrii_/wizard-js","dist-tags":{"latest":"2.1.1"},"versions":{"2.0.3":{"name":"@adrii_/wizard-js","version":"2.0.3","keywords":["javascript","npm","wizard","ui","component","accessibility","html5","vanilla-js","wizard-component","step-wizard","form-wizard","multi-step-form"],"author":{"name":"Adrián Villamayor Sánchez"},"license":"MIT","_id":"@adrii_/wizard-js@2.0.3","maintainers":[{"name":"adrii_","email":"adrian.villamayor@gmail.com"}],"contributors":[{"url":"https://github.com/AdrianVillamayor","name":"Adrián Villamayor Sánchez","email":"adrian.villamayor@gmail.com"}],"homepage":"https://github.com/AdrianVillamayor/Wizard-JS#readme","bugs":{"url":"https://github.com/AdrianVillamayor/Wizard-JS/issues"},"dist":{"shasum":"986b3b080a75660fd39ca9d698dfef3f073f83eb","tarball":"https://registry.npmjs.org/@adrii_/wizard-js/-/wizard-js-2.0.3.tgz","fileCount":8,"integrity":"sha512-2aYP1zGXqjUWNuzNQN00QC4TvK6OZbUClV0LklZkIFwX7TSwWhfGF6vRgypuQYE3PpgNy7HmbVE8vVf/cX4oXQ==","signatures":[{"sig":"MEQCICsAO3AMlxvvEU9uwe3ZvXv4MIJyLedrgzsaGbexkO/UAiAa3FTScWaw2xNrusPfVsHYu836sCAk5brChnl4YZEmlQ==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":80915},"main":"dist/index.js","module":"dist/index.esm.js","engines":{"npm":">=6.14.4","node":">=12"},"exports":{".":{"import":"./dist/index.esm.js","require":"./dist/index.js"},"./style.css":"./dist/main.min.css","./package.json":"./package.json"},"funding":{"url":"https://github.com/sponsors/AdrianVillamayor","type":"github"},"gitHead":"dad4b28240c13c95d85ffe3bdf972bfc95ce8653","scripts":{"dev":"webpack --watch --config webpack/webpack.dev.js","build":"webpack --config webpack/webpack.prod.js && npm run build:src","start":"webpack serve --config webpack/webpack.dev.js","build:src":"babel src --out-dir lib --copy-files"},"_npmUser":{"name":"adrii_","email":"adrian.villamayor@gmail.com"},"repository":{"url":"git+https://github.com/AdrianVillamayor/Wizard-JS.git","type":"git"},"_npmVersion":"10.8.2","description":"A lightweight wizard UI component that supports accessibility and HTML5 in vanilla JavaScript.","directories":{"src":"src","test":"test"},"sideEffects":["*.css","*.scss"],"_nodeVersion":"21.7.2","_hasShrinkwrap":false,"devDependencies":{"sass":"^1.75.0","cssnano":"^6.1.2","postcss":"^8.4.38","webpack":"^5.91.0","@babel/cli":"^7.25.7","css-loader":"^7.1.1","@babel/core":"^7.22.9","sass-loader":"^14.2.1","tailwindcss":"^3.4.3","webpack-cli":"^5.1.4","autoprefixer":"^10.4.19","babel-loader":"^9.1.3","concurrently":"^8.2.0","style-loader":"^4.0.0","webpack-merge":"^5.9.0","postcss-import":"^16.1.0","postcss-loader":"^8.1.1","@babel/preset-env":"^7.22.9","clean-webpack-plugin":"^4.0.0","terser-webpack-plugin":"^5.3.10","mini-css-extract-plugin":"^2.9.0","css-minimizer-webpack-plugin":"^7.0.0","@babel/plugin-syntax-import-attributes":"^7.22.5"},"_npmOperationalInternal":{"tmp":"tmp/wizard-js_2.0.3_1729011779224_0.4204472493746394","host":"s3://npm-registry-packages"}},"2.1.1":{"name":"@adrii_/wizard-js","version":"2.1.1","description":"A lightweight wizard UI component that supports accessibility and HTML5 in vanilla JavaScript.","main":"dist/index.js","module":"dist/index.esm.js","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.esm.js","require":"./dist/index.js"},"./package.json":"./package.json","./style.css":{"types":"./dist/style.css.d.ts","default":"./dist/main.min.css"}},"sideEffects":["*.css","*.scss"],"scripts":{"build":"pnpm run build:lib && pnpm run build:types && pnpm run build:demo","build:lib":"vite build","build:types":"pnpm exec tsc --declaration --emitDeclarationOnly --declarationMap false --outDir dist --rootDir src src/global.d.ts src/index.ts src/core/*.ts && mkdir -p dist/styles && printf 'export {};\\n' > dist/styles/index.scss.d.ts && printf 'declare const css: string;\\nexport default css;\\n' > dist/style.css.d.ts","build:demo":"pnpm exec vite build --config demo/vite.config.ts","start":"pnpm exec vite --config demo/vite.config.ts","dev":"pnpm run start","typecheck":"pnpm exec tsc -p tsconfig.json --noEmit","smoke:pack":"mkdir -p test/wizard-js-pack && rm -f test/wizard-js-pack/package.tgz && pnpm pack --pack-destination test/wizard-js-pack && node -e \"const fs=require('fs');const path=require('path');const dir=path.resolve('test/wizard-js-pack');const tgz=fs.readdirSync(dir).find((file)=>file.endsWith('.tgz')&&file!=='package.tgz');if(!tgz) throw new Error('No tarball generated');fs.renameSync(path.join(dir,tgz), path.join(dir,'package.tgz'));\"","smoke:install:ts":"CI=true pnpm --dir test/ts install --no-frozen-lockfile","smoke:install:js":"CI=true pnpm --dir test/js install --no-frozen-lockfile","smoke:install:cjs":"CI=true pnpm --dir test/cjs install --no-frozen-lockfile","smoke:ts":"pnpm exec tsc -p test/ts/tsconfig.json --noEmit","smoke:js":"node test/js/index.js","smoke:cjs":"node test/cjs/index.js","smoke":"pnpm run build && pnpm run smoke:pack && pnpm run smoke:install:ts && pnpm run smoke:install:js && pnpm run smoke:install:cjs && pnpm run smoke:ts && pnpm run smoke:js && pnpm run smoke:cjs","browser:prepare":"pnpm run build && pnpm run smoke:pack && pnpm run smoke:install:ts && pnpm run smoke:install:js && pnpm run smoke:install:cjs","browser:ts":"pnpm exec vite test/ts --config test/vite.config.ts","browser:js":"pnpm exec vite test/js --config test/vite.config.ts","browser:cjs":"pnpm exec vite test/cjs --config test/vite.config.ts","browser:cdn":"pnpm exec vite test/cdn --config test/vite.config.ts"},"keywords":["javascript","npm","wizard","ui","component","accessibility","html5","vanilla-js","wizard-component","step-wizard","form-wizard","multi-step-form"],"author":{"name":"Adrián Villamayor Sánchez"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/AdrianVillamayor/Wizard-JS.git"},"bugs":{"url":"https://github.com/AdrianVillamayor/Wizard-JS/issues"},"homepage":"https://github.com/AdrianVillamayor/Wizard-JS#readme","funding":{"type":"github","url":"https://github.com/sponsors/AdrianVillamayor"},"packageManager":"pnpm@10.29.3","engines":{"node":">=20.0.0","pnpm":">=10.0.0"},"contributors":[{"name":"Adrián Villamayor Sánchez","email":"adrian.villamayor@gmail.com","url":"https://github.com/AdrianVillamayor"}],"devDependencies":{"@types/node":"^24.12.0","sass":"^1.98.0","typescript":"^5.9.3","vite":"^8.0.16"},"pnpm":{"overrides":{"picomatch":"^4.0.4"}},"directories":{"demo":"demo","src":"src"},"dependencies":{"@adrii_/wizard-js":"^2.0.3"},"gitHead":"975e5bf0bb8e3e00b38922fc1f62b875db978e2c","_id":"@adrii_/wizard-js@2.1.1","_nodeVersion":"24.16.0","_npmVersion":"11.13.0","dist":{"integrity":"sha512-KykxNpjk7bNko7sM2DS23sNPfHQs1TiXChA01IYUEFVv1lZ6vyVQyiDk+VrHY5Kiksex0FMBBTVT5vwXbGvATA==","shasum":"385b71a866d84bceab40f9ae9679cbac7eefc022","tarball":"https://registry.npmjs.org/@adrii_/wizard-js/-/wizard-js-2.1.1.tgz","fileCount":28,"unpackedSize":113460,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCV4m6ShYX+pabNp+VqqXYQdoNkhs41RMiWdS9Ln7NGggIgLGTPpfYXMXj/UFQ7RIsGoNAQcJCxiZTyBtNfrpqr2gg="}]},"_npmUser":{"name":"adrii_","email":"adrian.villamayor@gmail.com"},"maintainers":[{"name":"adrii_","email":"adrian.villamayor@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/wizard-js_2.1.1_1782397692820_0.06494701506515566"},"_hasShrinkwrap":false}},"time":{"created":"2024-10-15T17:02:59.078Z","modified":"2026-06-25T14:28:13.102Z","1.7.6":"2022-03-24T09:39:46.019Z","1.0.0":"2022-03-24T09:50:07.191Z","2.0.0":"2024-10-15T15:44:57.539Z","1.0.1":"2024-10-15T16:34:40.613Z","2.0.1":"2024-10-15T16:36:30.970Z","2.0.2":"2024-10-15T16:43:42.435Z","2.0.3":"2024-10-15T17:02:59.443Z","2.1.1":"2026-06-25T14:28:12.979Z"},"bugs":{"url":"https://github.com/AdrianVillamayor/Wizard-JS/issues"},"author":{"name":"Adrián Villamayor Sánchez"},"license":"MIT","homepage":"https://github.com/AdrianVillamayor/Wizard-JS#readme","keywords":["javascript","npm","wizard","ui","component","accessibility","html5","vanilla-js","wizard-component","step-wizard","form-wizard","multi-step-form"],"repository":{"type":"git","url":"git+https://github.com/AdrianVillamayor/Wizard-JS.git"},"description":"A lightweight wizard UI component that supports accessibility and HTML5 in vanilla JavaScript.","contributors":[{"name":"Adrián Villamayor Sánchez","email":"adrian.villamayor@gmail.com","url":"https://github.com/AdrianVillamayor"}],"maintainers":[{"name":"adrii_","email":"adrian.villamayor@gmail.com"}],"readme":"[![Build and Lint](https://github.com/AdrianVillamayor/Wizard-JS/actions/workflows/main.yml/badge.svg)](https://github.com/AdrianVillamayor/Wizard-JS/actions/workflows/main.yml)\n![Badge-glow](https://img.shields.io/badge/WizardJS-v2.1.1-blue?style=flat-square)\n[![jsDelivr hits (GitHub)](https://data.jsdelivr.com/v1/package/gh/AdrianVillamayor/Wizard-JS/badge)](https://www.jsdelivr.com/package/gh/AdrianVillamayor/Wizard-JS)\n![GitHub repo size](https://img.shields.io/github/repo-size/AdrianVillamayor/Wizard-JS?style=flat-square)\n\n# Wizard-JS\n\nA lightweight wizard UI component for accessible multi-step flows in vanilla JavaScript.\n\n## Features\n\n- Supports accessibility (ARIA-compliant).\n- Fully customizable wizard steps and navigation.\n- Works with both ES modules and CommonJS.\n- Built-in form validation and control.\n- Async step guards with `before_step_change`.\n- Conditional required fields using `data-require-if` attribute.\n- Dynamic required fields with `on-active-required` class.\n- Customizable validation highlighting.\n\n## Table of Contents\n\n- [Wizard-JS](#wizard-js)\n  - [Features](#features)\n  - [Table of Contents](#table-of-contents)\n  - [Installation](#installation)\n  - [Test Folder](#test-folder)\n  - [Usage](#usage)\n    - [CommonJS](#commonjs)\n    - [ES Modules](#es-modules)\n    - [Example HTML for Wizard](#example-html-for-wizard)\n    - [Launch the Wizard](#launch-the-wizard)\n    - [Restart the Wizard](#restart-the-wizard)\n    - [Update the Wizard](#update-the-wizard)\n    - [Lock and Unlock the Wizard](#lock-and-unlock-the-wizard)\n  - [Form Validation](#form-validation)\n    - [Required Fields](#required-fields)\n    - [Conditionally Required Fields](#conditionally-required-fields)\n    - [Dynamic Required Fields](#dynamic-required-fields)\n    - [Custom Validation Highlighting](#custom-validation-highlighting)\n  - [HTML Attributes](#html-attributes)\n    - [Data Title Attribute `[data-wz-title]`](#data-title-attribute-data-wz-title)\n    - [Data Require If Attribute `[data-require-if]`](#data-require-if-attribute-data-require-if)\n  - [Config Wizard](#config-wizard)\n    - [Async Step Hook](#async-step-hook)\n    - [i18n Options](#i18n-options)\n  - [Events Management](#events-management)\n    - [Wizard Ready Event](#wizard-ready-event)\n    - [Wizard Update Event](#wizard-update-event)\n    - [Lock and Unlock Events](#lock-and-unlock-events)\n    - [Navigation Events](#navigation-events)\n    - [Validation Error Event](#validation-error-event)\n    - [Pending Step Events](#pending-step-events)\n    - [Form Submission and Wizard Completion Events](#form-submission-and-wizard-completion-events)\n    - [Reset Event](#reset-event)\n  - [Demo](#demo)\n  - [Contributing](#contributing)\n  - [License](#license)\n    - [Thanks for your help! 🎉](#thanks-for-your-help-)\n\n## Installation\n\nYou can install the package from [npm](https://www.npmjs.com/package/@adrii_/wizard-js):\n\n```bash\nnpm install @adrii_/wizard-js\n```\n\n```bash\npnpm add @adrii_/wizard-js\n```\n\n```bash\nbun install @adrii_/wizard-js\n```\n\nFor <a href=\"https://www.jsdelivr.com/package/gh/AdrianVillamayor/Wizard-JS\" target=\"_blank\">CDN</a> usage:\n\n```html\n<link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/gh/AdrianVillamayor/Wizard-JS@latest/dist/main.min.css\">\n\n<script src=\"https://cdn.jsdelivr.net/gh/AdrianVillamayor/Wizard-JS@latest/dist/index.js\"></script>\n```\n\nFor production usage, it is better to pin a specific version instead of `@latest`:\n\n```html\n<link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/gh/AdrianVillamayor/Wizard-JS@2.0.3/dist/main.min.css\">\n\n<script src=\"https://cdn.jsdelivr.net/gh/AdrianVillamayor/Wizard-JS@2.0.3/dist/index.js\"></script>\n```\n\n## Test Folder\n\nThe repository includes a [`test/`](./test) folder with smoke examples that show how to consume the package in different environments:\n\n- [`test/ts`](./test/ts): TypeScript consumer using the packed tarball.\n- [`test/js`](./test/js): JavaScript ESM consumer using the packed tarball.\n- [`test/cjs`](./test/cjs): CommonJS consumer using the packed tarball.\n- [`test/cdn`](./test/cdn): browser example using jsDelivr CDN.\n- [`test/base.css`](./test/base.css): minimal visual base used only by the browser smoke examples.\n\nThe name `test/` is intentional here: these are not unit tests, but package consumption smoke tests.\n\nTo run the automated smoke checks:\n\n```bash\npnpm run smoke\n```\n\nTo run them one by one:\n\n```bash\npnpm run smoke:ts\npnpm run smoke:js\npnpm run smoke:cjs\n```\n\nTo prepare the browser examples:\n\n```bash\npnpm run browser:prepare\n```\n\nTo open each browser example with Vite:\n\n```bash\npnpm run browser:ts\npnpm run browser:js\npnpm run browser:cjs\npnpm run browser:cdn\n```\n\nBrowser examples available in `test/`:\n\n- [`test/ts/index.html`](./test/ts/index.html): TypeScript + package CSS.\n- [`test/js/index.html`](./test/js/index.html): JavaScript ESM + package CSS.\n- [`test/cjs/index.html`](./test/cjs/index.html): browser UMD/global test using the packaged UMD bundle installed in the fixture.\n- [`test/cdn/index.html`](./test/cdn/index.html): CDN/browser test using jsDelivr.\n\nNote about `cjs` in the browser:\n\n- [`test/cjs/index.js`](./test/cjs/index.js) validates CommonJS in Node.\n- [`test/cjs/index.html`](./test/cjs/index.html) validates the browser global/UMD bundle.\n\nThe CDN example can also be opened directly in a browser if you only want to test the published jsDelivr version.\n\n## Usage\n\n### CommonJS\n\n```javascript\nconst Wizard = require('@adrii_/wizard-js');\nconst myWizard = new Wizard({\n  /* your configuration here */\n});\n\nmyWizard.init();\n```\n\n### ES Modules\n\n```javascript\nimport Wizard from '@adrii_/wizard-js';\nconst myWizard = new Wizard({\n  /* your configuration here */\n});\n\nmyWizard.init();\n```\n\n### Example HTML for Wizard\n\nFor content-only wizards:\n\n```html\n<div class=\"wizard\">\n    <aside class=\"wizard-content container\">\n        <div class=\"wizard-step\">\n            <!-- Step content -->\n        </div>\n        <!-- More steps -->\n    </aside>\n</div>\n```\n\nFor wizards with form purpose, it manages the required fields and validates them:\n\n```html\n<form class=\"wizard\" method=\"POST\">\n    <aside class=\"wizard-content container\">\n        <div class=\"wizard-step\">\n            <input type=\"text\" name=\"name\" class=\"required\" placeholder=\"Enter a short campaign name\">\n        </div>\n        <!-- More steps -->\n    </aside>\n</form>\n```\n\n### Launch the Wizard\n\nTo **launch** the wizard:\n\n```javascript\nlet args = {\n    \"wz_class\": \".wizard\",\n    \"wz_nav_style\": \"dots\",\n    \"wz_button_style\": \".btn .btn-sm .mx-3\",\n    \"wz_ori\": \"vertical\",\n    \"buttons\": true,\n    \"navigation\": 'buttons',\n    \"finish\": \"Save!\"\n};\n\nconst wizard = new Wizard(args);\n\nwizard.init();\n```\n\n### Restart the Wizard\n\nTo **restart** the wizard:\n\n```javascript\nwizard.reset();\n```\n\n### Update the Wizard\n\nTo **update** the wizard, deleting or adding steps:\n\n```javascript\nwizard.update();\n```\n\n### Lock and Unlock the Wizard\n\nTo **lock** the wizard at a specific step:\n\n```javascript\nwizard.lock();\n```\n\nTo **unlock** the wizard:\n\n```javascript\nwizard.unlock();\n```\n\n## Form Validation\n\nWizard-JS includes built-in form validation for required fields.\n\n### Required Fields\n\nTo mark an input as required, add the `required` attribute or the `required` class:\n\n```html\n<input type=\"text\" name=\"email\" required>\n<!-- or -->\n<input type=\"text\" name=\"email\" class=\"required\">\n```\n\n### Conditionally Required Fields\n\nYou can make fields conditionally required based on the value of another field using the `data-require-if` attribute.\n\nThe format is `data-require-if=\"fieldID:requiredValue\"`.\n\n```html\n<input type=\"checkbox\" id=\"subscribe\" name=\"subscribe\">\n\n<input type=\"email\" name=\"email\" data-require-if=\"subscribe:true\" placeholder=\"Enter your email\">\n```\n\nIn this example, the email field becomes required if the checkbox with id `subscribe` is checked (`true`).\n\n### Dynamic Required Fields\n\nUse the `on-active-required` class to mark fields that become required only when the step is active.\n\n```html\n<input type=\"text\" name=\"username\" class=\"on-active-required\" placeholder=\"Enter your username\">\n```\n\n### Custom Validation Highlighting\n\nYou can customize the validation highlighting behavior:\n\n- `highlight`: Set to `true` to enable highlighting invalid fields.\n- `highlight_time`: Duration (in milliseconds) to display the highlight. Default is `1000`.\n- `highlight_type`: An object to define the classes for different highlight types.\n\nExample:\n\n```javascript\nlet args = {\n    /* Other configurations */\n    \"highlight\": true,\n    \"highlight_time\": 1500,\n    \"highlight_type\": { error: \"error\", warning: \"warning\", success: \"success\", info: \"info\" }\n};\n```\n\n## HTML Attributes\n\n### Data Title Attribute `[data-wz-title]`\n\nSet the step title for the navigation. If left blank, the system will automatically add `Step + step number` as the title.\n\n```html\n<div class=\"wizard-step\" data-wz-title=\"Configuration\">\n    <!-- Step content -->\n</div>\n```\n\n### Data Require If Attribute `[data-require-if]`\n\nDefine conditional required fields based on another field's value.\n\n```html\n<input type=\"email\" name=\"email\" data-require-if=\"subscribe:true\" placeholder=\"Enter your email\">\n```\n\n## Config Wizard\n\nOptions allowing you to modify the behavior and actions:\n\n| Parameter         | Type    | Default                                                                    | Definition / Value                                             |\n| ----------------- | ------- | -------------------------------------------------------------------------- | -------------------------------------------------------------- |\n| `wz_class`        | String  | `.wizard`                                                                  | Wizard main container target                                   |\n| `wz_ori`          | String  | `.horizontal`                                                              | Wizard orientation (`.horizontal`, `.vertical`)                |\n| `wz_nav`          | String  | `.wizard-nav`                                                              | Navigation container class                                     |\n| `wz_nav_style`    | String  | `dots`                                                                     | Style of navigation steps (`dots`, `tabs`, `progress`)         |\n| `wz_content`      | String  | `.wizard-content`                                                          | Body container class                                           |\n| `wz_buttons`      | String  | `.wizard-buttons`                                                          | Action button container class                                  |\n| `wz_button`       | String  | `.wizard-btn`                                                              | Class of Previous, Next, and Finish action buttons             |\n| `wz_button_style` | String  | `.btn`                                                                     | Basic button style                                             |\n| `wz_step`         | String  | `.wizard-step`                                                             | Class for both nav and body steps                              |\n| `wz_form`         | String  | `.wizard-form`                                                             | Class of the form that contains the wizard                     |\n| `wz_next`         | String  | `.next`                                                                    | Class of Next action button                                    |\n| `wz_prev`         | String  | `.prev`                                                                    | Class of Prev action button                                    |\n| `wz_finish`       | String  | `.finish`                                                                  | Class of Finish action button                                  |\n| `wz_highlight`    | String  | `.highlight-error`                                                         | Class for highlights when validation errors occur              |\n| `current_step`    | Number  | `0`                                                                        | Active wizard step                                             |\n| `steps`           | Number  | `0`                                                                        | Number of wizard steps                                         |\n| `highlight_time`  | Number  | `1000`                                                                     | Display time for validation highlight (in milliseconds)        |\n| `navigation`      | String  | `all`                                                                      | Navigation mode (`buttons`, `nav`, `all`)                      |\n| `buttons`         | Boolean | `true`                                                                     | Show or hide the action buttons                                |\n| `nav`             | Boolean | `true`                                                                     | Show or hide the header navigation                             |\n| `highlight`       | Boolean | `true`                                                                     | Enable or disable field highlighting on validation errors      |\n| `next`            | String  | `Next`                                                                     | Text for the Next button                                       |\n| `prev`            | String  | `Prev`                                                                     | Text for the Prev button                                       |\n| `finish`          | String  | `Submit`                                                                   | Text for the Finish button                                     |\n| `before_step_change` | Function | `null`                                                                  | Hook executed before moving forward. Can return `false` or a rejected promise to block the step change |\n| `bubbles`         | Boolean | `true`                                                                     | Enable or disable event bubbling for custom events             |\n| `highlight_type`  | Object  | `{ error: \"error\", warning: \"warning\", success: \"success\", info: \"info\" }` | Classes for different validation highlight effects             |\n| `i18n`            | Object  | Various                                                                    | Internationalization messages for errors, titles, and warnings |\n\n### Async Step Hook\n\nUse `before_step_change` when you need to perform async work before allowing the wizard to move to the next step.\n\n```javascript\nconst wizard = new Wizard({\n    wz_class: \".wizard\",\n    before_step_change: async ({ currentStepElement, isAsyncStep }) => {\n        if (!isAsyncStep) {\n            return true;\n        }\n\n        const stepId = currentStepElement?.getAttribute(\"data-id\");\n\n        if (stepId === \"campaign\") {\n            const response = await fetch(\"/api/check-campaign\", {\n                method: \"POST\"\n            });\n\n            return response.ok;\n        }\n\n        if (stepId === \"notification\") {\n            const title = currentStepElement\n                ?.querySelector('input[name=\"title\"]')\n                ?.value;\n\n            return title === \"LoR\";\n        }\n\n        return true;\n    }\n});\n```\n\nTo mark a step as async-only, add either `data-wz-async=\"true\"` or `data-async-step=\"true\"` to the current `.wizard-step`.\n\nIf you have more than one async step, prefer identifying each step with a stable attribute such as `data-id` instead of relying only on the numeric index.\n\n```html\n<div class=\"wizard-step\" data-id=\"campaign\" data-wz-async=\"true\"></div>\n<div class=\"wizard-step\" data-id=\"notification\" data-wz-async=\"true\"></div>\n```\n\nThe hook context exposes:\n\n- `currentStep`\n- `nextStep`\n- `currentStepElement`\n- `nextStepElement`\n- `trigger`\n- `isAsyncStep`\n- `wizard`\n\nWhile the hook is pending, the wizard root gets `data-wz-pending=\"true\"` and extra forward clicks are ignored.\n\n### i18n Options\n\nThe `i18n` object allows you to define custom error messages for different wizard actions:\n\n- `empty_wz`: \"No item has been found with which to generate the Wizard.\"\n- `empty_nav`: \"Nav does not exist or is empty.\"\n- `empty_content`: \"Content does not exist or is empty.\"\n- `empty_html`: \"Undefined or null content cannot be added.\"\n- `empty_update`: \"Nothing to update.\"\n- `no_nav`: \"Both the nav and the buttons are disabled, there is no navigation system.\"\n- `form_validation`: \"One or more of the form fields are invalid.\"\n- `diff_steps`: \"Discordance between the steps of nav and content.\"\n- `random`: \"There has been a problem, check the configuration and use of the wizard.\"\n- `already_defined`: \"This item is already defined.\"\n- `title`: \"Step\" (used for default step titles if not specified in the HTML).\n\n## Events Management\n\nWizard-JS provides several events to help you manage and respond to user interactions.\n\n### Wizard Ready Event\n\nTo identify when the wizard is fully generated and loaded.\n\n```javascript\ndocument.addEventListener(\"wz.ready\", function (e) {\n    console.log(`Target:`, e.detail.target); // .wizard\n    console.log(`DOM Element:`, e.detail.elem); // DOM element\n});\n```\n\n### Wizard Update Event\n\nTriggered when the wizard is updated.\n```javascript\nlet wz_class = \".wizard\";\nlet $wz_doc = document.querySelector(wz_class)\n```\n\n```javascript\n$wz_doc.addEventListener(\"wz.update\", function (e) {\n    console.log(`Target:`, e.detail.target);\n    console.log(`DOM Element:`, e.detail.elem);\n});\n```\n\n### Lock and Unlock Events\n\nWhen the wizard is locked:\n\n```javascript\n$wz_doc.addEventListener(\"wz.lock\", function (e) {\n    alert(\"Wizard is locked\");\n});\n```\n\nWhen the wizard is unlocked:\n\n```javascript\n$wz_doc.addEventListener(\"wz.unlock\", function (e) {\n    alert(\"Wizard is unlocked\");\n});\n```\n\n### Navigation Events\n\nMoving to the previous step:\n\n```javascript\n$wz_doc.addEventListener(\"wz.btn.prev\", function (e) {\n    alert(\"Previous Step\");\n});\n```\n\nMoving to the next step:\n\n```javascript\n$wz_doc.addEventListener(\"wz.btn.next\", function (e) {\n    alert(\"Next Step\");\n});\n```\n\nNavigating forward with the navbar:\n\n```javascript\n$wz_doc.addEventListener(\"wz.nav.forward\", function (e) {\n    alert(\"Forward Navigation\");\n});\n```\n\nNavigating backward with the navbar:\n\n```javascript\n$wz_doc.addEventListener(\"wz.nav.backward\", function (e) {\n    alert(\"Backward Navigation\");\n});\n```\n\n### Validation Error Event\n\nTriggered when there is an error validating the data of the active form step.\n\n```javascript\n$wz_doc.addEventListener(\"wz.error\", function (e) {\n    console.log(`ID:`, e.detail.id); // form_validation\n    console.log(`Message:`, e.detail.msg); // Form validation message\n    console.log(`Target:`, e.detail.target); // Array of invalid elements\n});\n```\n\n### Pending Step Events\n\nTriggered when `before_step_change` starts, finishes or throws an error.\n\n```javascript\n$wz_doc.addEventListener(\"wz.pending\", function (e) {\n    console.log(\"Pending step change\", e.detail.currentStep, e.detail.nextStep);\n});\n\n$wz_doc.addEventListener(\"wz.pending.done\", function (e) {\n    console.log(\"Step change allowed:\", e.detail.allowed);\n});\n\n$wz_doc.addEventListener(\"wz.pending.error\", function (e) {\n    console.error(\"Async step failed\", e.detail.error);\n});\n```\n\n### Form Submission and Wizard Completion Events\n\nIf it is a form, at the end it will fire the following event:\n\n```javascript\n$wz_doc.addEventListener(\"wz.form.submit\", function (e) {\n    alert(\"Form Submitted\");\n});\n```\n\nIf it is not a form, at the end it will fire the following event:\n\n```javascript\n$wz_doc.addEventListener(\"wz.end\", function (e) {\n    alert(\"Wizard is finished\");\n});\n```\n\n### Reset Event\n\nWhen the wizard is restarted:\n\n```javascript\n$wz_doc.addEventListener(\"wz.reset\", function (e) {\n    alert(\"Wizard has restarted\");\n});\n```\n\n## Demo\n\nTry it on CodePen:\n\n[![Codepen](https://user-images.githubusercontent.com/29653964/116972608-8f6bca80-acbb-11eb-98c1-8a3b19705de1.png)](https://codepen.io/adrianvillamayor/pen/VwWPVME)\n\nThe local repo demo also includes an async example with multiple async steps:\n\n- `campaign`: only advances when `dropdown === \"other\"`\n- `notification`: only advances when `title === \"LoR\"`\n\nYou can run it with:\n\n```bash\npnpm run dev\n```\n\n\n## Contributing\n\nPull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.\n\nPlease make sure to update tests as appropriate.\n\n## License\n\n[MIT](https://github.com/AdrianVillamayor/Wizard-JS/blob/main/LICENSE)\n### Thanks for your help! 🎉\n","readmeFilename":"README.md"}