JavaScript Widgets After an AI-to-WordPress Migration: Keep the Useful Behaviour
By Daniel Carter, Senior AI & Web Development Consultant
Convert2WP – Convert your AI website to WordPress
The visual conversion of an AI-built website and the migration of its browser behaviour are different jobs. A screenshot shows an accordion, a price calculator and a booking panel as parts of the same page. In the source project, those elements may depend on different libraries, internal state and remote services. Copying the generated JavaScript bundle into WordPress can appear to preserve everything, but it often introduces a second application competing with the theme. The result is harder to edit and harder to diagnose than either original system.
A better approach is selective. Keep behaviours that serve a real visitor need, replace simple interactions with native or well-supported WordPress equivalents, and isolate genuinely custom widgets. This guide focuses on that decision process. It does not assume that a frontend conversion transfers server functions, payment processing or authentication. Those services need their own supported integration. The objective is a WordPress page that retains useful behaviour without depending on the hidden assumptions of its previous deployment.
Describe the interaction before choosing the library
For each important widget, write what a visitor can do and what result they should see. A pricing calculator might accept a team size and display an estimate. A booking widget might query availability from a separate service and redirect to its checkout. These are not equivalent migrations. The first may be a small browser calculation; the second relies on service availability, authentication and business rules. Describing the behaviour makes the boundary visible before you spend time reproducing the surrounding animation.
Record loading, empty and failure states as part of the behaviour. A widget that only works when a request succeeds immediately is not complete enough for production. Also decide what should happen without JavaScript. A calculator can show a base price and a contact option; a booking panel can provide a direct link to the scheduling service. The fallback does not need to reproduce every interaction. It should leave the page understandable and give the visitor a reasonable next step.
Use native building blocks for ordinary interactions
An accordion does not automatically justify a React runtime. A suitable core block, a semantic details element or a maintained block extension may provide the behaviour with much less code. The same applies to navigation toggles and basic tabs, although tabs require careful keyboard and focus handling. Compare actual requirements rather than matching the original library name. A tiny difference in animation timing is usually less important than predictable keyboard access and an editor who can update the content safely.
For custom blocks, consider the WordPress Interactivity API when the supported WordPress version and project requirements make it appropriate. It provides a WordPress-oriented model for interactive state, but it is not a magic translator for arbitrary React components. Existing code still needs adaptation. If you retain React for a substantial widget, mount it inside one dedicated root instead of trying to hydrate an entire WordPress document. Keep the widget's ownership of the DOM separate from the theme and other blocks.
Load scripts through WordPress, not pasted page fragments
Register and enqueue assets through the supported WordPress APIs or block metadata. This gives the platform a consistent view of dependencies and allows conditional loading where appropriate. Inline script tags pasted into several pages are difficult to version, easy to duplicate and can be removed by editor sanitisation. A small custom plugin or block is usually the better home for reusable behaviour. Keep content editable in the page while keeping executable code in a controlled release artifact.
Pay attention to dependency order. A script that assumes a global library is already available may work in an uncached preview and fail after optimisation changes loading order. Declaring dependencies is more reliable than relying on incidental placement. Deferred or asynchronous loading should follow the widget's actual requirements; adding async to every script is not a universal performance fix. Likewise, verify compatibility before enabling a plugin that delays all JavaScript until the first interaction. Some widgets need to initialise before a visitor touches them.
Prevent duplicate initialisation and namespace collisions
A WordPress page can contain the same block more than once, and editors may preview or re-render it while working. Initialise each widget instance deliberately. Avoid selecting one global identifier and assuming there will only ever be a single instance. Mark an element as initialised or manage a lifecycle that can safely run again. Remove listeners and observers when an instance is destroyed if the environment requires it. Repeated initialisation is a common source of calculations firing twice or menus opening and immediately closing.
Scope styles and DOM queries to the widget's container. An AI-generated selector such as button or input may look harmless in the original isolated app but alter the WordPress toolbar, form plugin or checkout when imported globally. Use a stable widget class or block namespace. Do the same for global variables and custom events. If two widgets exchange messages, define the event payload rather than passing whatever happens to exist in local state. Explicit boundaries make later changes much less fragile.
Keep secrets and trusted decisions off the browser
Browser code is public. A key embedded in a JavaScript file, an HTML data attribute or a network request is visible to visitors. Use only credentials specifically designed to be public, and keep private service credentials on the server. When a widget requests a price or creates a reservation, the receiving service must validate the request and apply its own permissions. A disabled button or hidden field is a user interface decision, not an access control mechanism.
For logged-in WordPress requests, use the authentication and permission patterns appropriate to the endpoint. A nonce can help protect against cross-site request forgery in its intended context, but it is not a substitute for checking user capabilities. For public widgets, rate limits and input validation may be necessary even when no account is required. If the widget calls another domain, confirm its CORS policy and cookie expectations. Cross-origin failures are often configuration problems rather than bugs in the visual component.
Make state changes accessible and predictable
A modal needs more than a dark background and a close icon. Focus should move into it, remain appropriately contained while it is modal, and return to the element that opened it. Escape handling and an accessible name matter. Calculators and filters should announce meaningful result changes without overwhelming screen-reader users on every keystroke. Prefer native controls where they fit, and give custom controls the necessary roles and keyboard behaviour. A visually accurate widget can still be unusable for someone navigating without a mouse.
Respect reduced-motion preferences and avoid animations that are required to reveal essential content. An imported scroll effect may leave sections invisible if its initialisation fails. Keep content visible by default, then enhance it when the script is ready. Similarly, loading placeholders should have stable dimensions so a remote widget does not push the reader down the page after rendering. These choices improve both accessibility and perceived quality without requiring the original animation framework to survive the migration.
Give each widget a manageable service contract
Document the inputs, external services, supported browser assumptions and expected failure behaviour for a custom widget. Include who maintains it and where its source lives. A WordPress administrator should not need to reverse engineer a minified bundle to discover which scheduling account powers the page. If a vendor supplies an official embed, evaluate it first, including its privacy implications and accessibility. An iframe can isolate code effectively, but height changes, permissions and communication with the parent page still need deliberate handling.
Use a few representative scenarios to review the migrated widget: normal input, invalid input, a slow service and a repeated instance. Focus on the meaningful behaviour rather than asserting that every click has been inspected. Convert2WP.net can help with the presentation layer, while custom browser logic remains a separate engineering decision. Small visual imperfections are normal and often easy to adjust through a plugin or a small stylesheet. The important outcome is that retained behaviour has a clear owner and no longer depends on an abandoned application shell.