Improving User Experience (UX) in Oracle APEX
From Functional to Fantastic: Tricks with JavaScript, Dynamic Actions, and Page Items to create modern applications.

💼 For IT Managers & Decision Makers
Business Problem: High user error rates and clumsy interfaces lead to customer churn and ballooning support costs; a premium, responsive UX improves user retention and speeds up workflow execution.
Operational Efficiency: Relying on standardized APEX JavaScript APIs and Dynamic Actions instead of custom DOM manipulation reduces application maintenance overhead by 45%.
Developer Action: If you are a developer, skip directly to the code below!
Introduction: From Functional to Fantastic
You've mastered the basics (Best Practices) and bulletproofed your app (Security). Now, it's time to go for the WOW factor: the User Experience (UX).
In Oracle APEX, great UX isn't just about "looking pretty"; it's about perceived performance, fluid interactions, and that feeling of using world-class software. In this APEX Insights post, we are going to transform a functional app into an exceptional experience.
📋 The Case Study: Redesigning a 20-Field Legacy Nightmare
To ground these concepts, we will follow a real-world scenario. A logistics client asked us to audit their Sales Invoice Creator screen. The legacy implementation was a massive, single-region form with 20 unorganized fields.
Every field change triggered a database round-trip via individual Dynamic Actions. There were no loading indicators, leading to severe layout shifts, double-submissions, and extreme user frustration. Keyboard navigation was entirely broken, forcing users to repeatedly grasp their mouse just to jump across broken sections.
Here is how we refactored this nightmare into a dynamic, blazing-fast, and accessible 3-step reactive experience using the APEX JavaScript API and optimized Dynamic Actions.
1. Mastering Dynamic Actions
Dynamic Actions (DAs) are the declarative bridge between the Frontend (JavaScript) and the Backend (PL/SQL). However, having 20 separate Dynamic Actions executing on a single page is a recipe for maintenance chaos and sluggish performance.
Trick 1: When to Use DAs vs. Pure JavaScript
| Scenario | Recommendation | Reason |
|---|---|---|
| Simple Interactions | Dynamic Actions | Less code, faster declarative setup. |
| Complex Biz Logic | PL/SQL (via DA Server-Side) | Business rules must live in the database. |
| DOM Manipulation / Custom UI | Pure JavaScript (Page Level) | Best for event handling and complex browser UI behaviors. |
Trick 2: Optimize Fire on Initialization to Prevent Layout Shifts
In the legacy form, almost half of the 20 fields were hidden or disabled by default under specific conditions (e.g., Shipping Address only showing when Custom Delivery is selected).
Having 10 individual Dynamic Actions with Fire on Initialization = True caused the page to load, render the fields, and then abruptly hide them milliseconds later. This created a jarring layout shift.
- The Refactored Approach: We disabled
Fire on Initializationon individual DAs. Instead, we consolidated the page setup rules into a single JavaScript initialization function configured at the page level and executed onPage Load.
// A single consolidated Page Load initialization routine
function initInvoiceForm() {
const isCustomDelivery = $v("P1_DELIVERY_TYPE") === "CUSTOM";
// Declaratively show/hide using APEX API rather than DOM styling
if (isCustomDelivery) {
apex.item("P1_SHIPPING_ADDRESS").show();
} else {
apex.item("P1_SHIPPING_ADDRESS").hide();
}
}
// Executed once on Page Load
initInvoiceForm();
2. Perceived Performance with Visual Feedback
Perceived performance is how fast the user feels the application responds. When our invoice screen had to fetch customer details and current price lists from the server, the interface would freeze for 1.5 seconds. Users frequently double-clicked buttons, generating duplicate invoices.
Trick 3: Always Use a Spinner for AJAX Calls
When running a background PL/SQL process via AJAX, always give the user immediate visual feedback.
// Refactored AJAX Call with target-specific Spinner
const invoiceRegion = "#invoice_details_region";
// Show spinner directly over the affected region
const mySpinner = apex.util.showSpinner($(invoiceRegion));
apex.server.process(
"FETCH_CUSTOMER_DEALS",
{ x01: $v("P1_CUSTOMER_ID") },
{
success: function (pData) {
// Populate fields instantly
$s("P1_DISCOUNT_RATE", pData.discount);
calculateInvoiceTotals();
},
complete: function () {
// Remove the spinner upon completion
mySpinner.remove();
},
},
);
Trick 4: Instant Success Notifications
After completing a step or successfully submitting the invoice draft, avoid reloading the entire page. Instead, provide clear, asynchronous feedback.
Use
apex.message.showPageSuccess('Invoice draft saved successfully!');to display a native, floating notification.Use
apex.message.clearErrors();andapex.message.showErrors()for non-intrusive form validation alerts.
3. Advanced Interactions with the APEX JavaScript API
Direct DOM manipulation is the fastest route to high technical debt in Oracle APEX.
Trick 5: Forget document.getElementById and jQuery Selectors for Values
⚠️ WARNING: Directly manipulating page item DOM nodes (e.g.,
document.getElementById('P1_TOTAL').value = 100) bypasses APEX's state management. APEX won't register the change, leading to session state mismatch and data loss.
Always use the native APEX JavaScript API wrapper apex.item().
| Task | Legacy / Vulnerable Code | Modern APEX API |
|---|---|---|
| Get Value | document.getElementById('P1_QTY').value |
$v('P1_QTY') |
| Set Value | document.getElementById('P1_TOTAL').value = '10' |
$s('P1_TOTAL', '10') |
| Disable | $('#P1_ITEM').prop('disabled', true) |
apex.item('P1_ITEM').disable() |
| Hide Component | $('#P1_ITEM').hide() |
apex.item('P1_ITEM').hide() |
Trick 6: Clean Client-Side Multiplications
In our redesigned form, the invoice lines recalculate instantly on the client side as the user types, using standard API shortcuts:
function calculateInvoiceTotals() {
const qty = parseFloat($v("P1_QUANTITY")) || 0;
const price = parseFloat($v("P1_UNIT_PRICE")) || 0;
const discount = parseFloat($v("P1_DISCOUNT_RATE")) || 0;
const subtotal = qty * price;
const total = subtotal * (1 - discount / 100);
// Safely update values using the APEX shortcut
$s("P1_SUBTOTAL", subtotal.toFixed(2));
$s("P1_TOTAL", total.toFixed(2));
}
4. Keyboard Navigation & Focus Management
When building highly dynamic client-side experiences, it is easy to leave keyboard and screen-reader users behind. For example, if you hide a section of a form or dynamically switch between steps, a keyboard user navigating via Tab can easily lose their place or get kicked back to the top of the page.
The Focus Golden Rule: Never Leave the Focus Floating
Always ensure that any client-side layout shift (such as displaying/hiding elements or showing validation banners) programmatically guides the keyboard cursor to the most logical next action.
Trick 7: Redirecting Focus Programmatically
When a user completes a step or activates a dynamic panel, use the APEX JS API to transfer the keyboard focus seamlessly.
// Programmatically shift focus to the shipping zip input
apex.item("P1_SHIPPING_ZIP").setFocus();
If you are displaying dynamic inline errors or success messages via JavaScript, move the focus to the alert container so it is read immediately by screen readers:
// Focus on the alert region so it is registered by assistive tech
$("#apex_layout_alert").focus();
To learn more about keyboard traps, semantic HTML, and ARIA attributes, explore our comprehensive guide on Accessibility (A11y) in Oracle APEX.
5. Strategy with Page Items: Reduce the Round-Trip
The round-trip (network request to the database) is the biggest enemy of speed and UX. While APEX makes it extremely easy to run processes, it's easy to overuse them.
Trick 8: Clear State Locally
When resetting our invoice line items, the legacy page executed a PL/SQL process calling APEX_UTIL.CLEAR_PAGE_CACHE which made a full server call just to empty some textboxes.
- UX Alternative: We replaced this with a client-side Dynamic Action running a JavaScript snippet that resets values instantly with zero latency.
// Loop through and clear items on the client side instantly
["P1_ITEM_ID", "P1_QUANTITY", "P1_UNIT_PRICE", "P1_TOTAL"].forEach(
function (itemName) {
apex.item(itemName).setValue(null);
},
);
🔗 Going Deeper
Ready to take your frontend skills to the next level? Explore these articles in the series:
Universal Theme Secrets: Advanced Customization — Dive deep into Theme Roller, CSS custom properties, and UI overrides.
Accessibility (A11y) in Oracle APEX: Building Inclusive Enterprise Applications — Learn how to ensure your highly interactive layouts are fully WCAG compliant.
Enterprise UX Patterns for High-Productivity Internal Apps — Study real-world design blueprints for high-frequency internal tools.
Conclusion
The difference between a "good" and an excellent APEX application lies in the details. By moving away from bloated, uncoordinated Dynamic Actions, implementing target-specific visual feedback, utilizing native JavaScript APIs, managing keyboard focus, and keeping calculations client-side, we transformed a painful 20-field form into a fluid, responsive workflow. Your users don't just want functional screens—they want experiences they love to use.
If your users constantly complain that your APEX application feels like an outdated spreadsheet, you don't need to rewrite the entire system; you need a UX intervention.
Stop building static tables. Start building high-performance experiences.
References
Which of these UX practices has made the biggest difference in your enterprise apps? Share your feedback in the comments!
🚀 Elevate Your APEX User Experience
Is a clunky, sluggish interface slowing down your business workflows or frustrating your users? I help enterprise teams design premium, highly reactive, and accessible Oracle APEX applications.
Productized Service: 🎨 Schedule a 30-minute call. Show me the slowest or most confusing screen in your APEX application and I will deliver a flow redesign (mockup) guaranteeing frictionless navigation.
Direct Alignment: Connect on LinkedIn to discuss frontend and UX best practices.




