Making Dashboard Cards Interactive: Wiring UI State to Tab Navigation in JADA's Maintenance Hub

We recently identified a UX friction point in the JADA maintenance dashboard: the "Total Tasks" summary card displayed a count (82 tasks) but wasn't clickable. Users had to manually navigate to the Tasks tab to see the underlying data. This post details how we made that card interactive and routed clicks to the correct dashboard view, along with the infrastructure pattern we used to deploy the change.

The Problem

The maintenance hub's dashboard had several summary cards displayed at the top—Total Tasks, Systems Status, Upcoming Maintenance, etc. These cards served as KPIs but didn't function as navigation shortcuts. Clicking the "Total Tasks: 82" card did nothing, forcing users to find and click the Tasks tab manually. For a system designed around quick, at-sea decision-making, this extra friction added cognitive load.

Technical Architecture Overview

The JADA maintenance hub is a single-page application (SPA) built with vanilla JavaScript and served from an S3 bucket with CloudFront caching:

  • Storage: s3://jada-maintenance-hub-prod/index.html
  • CDN: CloudFront distribution (ID: E3V2X8H9K2L, masked for security)
  • Tab System: JavaScript-based view switching using data attributes and a switch statement
  • State Management: localStorage for persistent UI state between sessions

The dashboard uses a tab-based layout where each major section (Dashboard, Systems, Tasks, Maintenance Schedule) is toggled via a switchTab(tabName) function. The Tasks data lives in the Systems tab's task table, not the Dashboard tab itself.

Finding the Implementation Details

First, we downloaded the current index.html from S3 to understand the structure:

aws s3 cp s3://jada-maintenance-hub-prod/index.html ./maintenance_index.html

We then searched for the Total Tasks card markup and the tab navigation logic:

# Find the card definition
grep -n "Total Tasks" maintenance_index.html

# Find the switchTab function
grep -n "switchTab" maintenance_index.html

The Total Tasks card was rendered as a static <div class="info-card">. The tab system used a switchTab(tabName) function that accepted values like 'dashboard', 'systems', 'tasks', and 'maintenance'. The actual task table was rendered in the Systems tab, not the Dashboard tab—a design choice made to consolidate all system-level data in one view.

Implementation: Making the Card Clickable

We made three key changes to the HTML:

1. Wrap the Total Tasks Card in a Clickable Element

We changed the card from a passive div to an interactive element with an onclick handler:

<div class="info-card info-card-link" onclick="switchTab('systems')" role="button" tabindex="0">
  <div class="card-title">Total Tasks</div>
  <div class="card-value">82</div>
  <div class="card-subtitle">Tracked items</div>
</div>

Key attributes:

  • onclick="switchTab('systems')": Routes the click to the Systems tab where task data is actually rendered
  • class="info-card-link": New CSS class for styling clickable cards differently from static ones
  • role="button" and tabindex="0": Accessibility markers so screen readers and keyboard navigation recognize this as an interactive element

2. Add CSS for Visual Feedback

We added a new CSS class to give users visual and interactive feedback:

.info-card-link {
  cursor: pointer;
  transition: all 0.2s ease;
  user-select: none;
}

.info-card-link:hover {
  background-color: rgba(52, 152, 219, 0.1);
  box-shadow: 0 4px 12px rgba(52, 152, 219, 0.2);
  transform: translateY(-2px);
}

.info-card-link:active {
  transform: translateY(0);
  box-shadow: 0 2px 6px rgba(52, 152, 219, 0.15);
}

This provides:

  • cursor: pointer: Signals clickability on hover
  • Hover elevation with shadow and subtle color change: Matches modern UI patterns
  • Active state depression: Tactile feedback that the click registered
  • Smooth transitions: Prevents jarring visual changes

3. Ensure switchTab() Handles the Navigation

The existing switchTab() function already handled tab switching via a switch statement. We verified it had a case for 'systems' and that the task table was rendered in that tab's content area. No changes to the JavaScript logic were needed.

Deployment Pipeline

We used our standard deployment process:

  1. Local Edit: Modified maintenance_index.html with the clickable card and CSS
  2. S3 Upload: Pushed the updated file back to the S3 bucket
  3. CloudFront Invalidation: Created a cache invalidation for /* to force edge locations to fetch the new version
# Upload to S3
aws s3 cp maintenance_index.html s3://jada-maintenance-hub-prod/index.html

# Invalidate CloudFront cache
aws cloudfront create-invalidation \
  --distribution-id E3V2X8H9K2L \
  --paths "/*"

The CloudFront invalidation is critical because:

  • S3 is the origin, but CloudFront caches all requests at edge locations worldwide
  • Without invalidation, users would see the old version for up to 24 hours (our cache TTL)
  • Invalidation typically propagates to all edge locations within 30–60 seconds

Why We Chose This Approach

Routing to Systems tab instead of Tasks tab: The task table is rendered in the Systems tab, which also shows system health and maintenance status. This design decision (made in a prior iteration) groups all operational data together. A card click to the Systems tab gives users the full context, not just a filtered view.

CSS hover states: We prioritized lightweight visual feedback over heavier animations. On a sailing vessel with potentially spotty internet, snappy UI interactions matter more than elaborate effects.

Accessibility attributes: role="button" and tabindex="0" ensure users with screen readers understand the card is interactive, and keyboard-only users can tab to and activate it with Enter.

Testing and