Making Dashboard Cards Interactive: Implementing Clickable Navigation in the JADA Maintenance Hub

Overview

During this session, we enhanced the JADA Maintenance Hub dashboard by making the "Total Tasks" card clickable and interactive. The card now functions as a navigation element that seamlessly switches the user to the Tasks tab, improving the user experience and reducing friction when accessing frequently-needed maintenance data. This required coordinated changes across the S3-hosted frontend, CloudFront caching layer, and DOM event handling logic.

What Was Done

The primary goal was to eliminate an extra click: users clicking the prominent "Total Tasks 82" card should immediately see the task table rather than having to click a separate tab. This is a small UX improvement with measurable impact on workflow efficiency aboard JADA.

  • Identified the source file: The maintenance hub HTML lives in an S3 bucket (maintenance subdomain), not in the local repository
  • Located the target DOM element: Found the "Total Tasks" card structure and understood how the tab navigation system works
  • Implemented clickable behavior: Wrapped the card markup to make it respond to clicks and added CSS styling for affordance
  • Deployed changes: Pushed the updated HTML to S3 and invalidated the CloudFront distribution cache
  • Verified in production: Confirmed the card click now triggers the `switchTab('systems')` function

Technical Details

File Structure and Discovery

The maintenance hub's frontend lives at a non-standard location for this project. Rather than being part of the main git repository at `/Users/cb/Documents/repos/sites/queenofsandiego.com/`, the HTML is deployed directly to S3 and served through CloudFront. This architecture decision decouples frontend changes from the main site deployment pipeline, allowing rapid updates without full site builds.

The relevant file path in S3:

s3://maintenance-hub-bucket/index.html

Search commands helped locate this: we searched for "Total Tasks" text across the codebase, then cross-referenced against the local filesystem and S3 buckets. Once we confirmed the file lived in S3, we downloaded it locally for editing.

Tab Navigation System Architecture

The maintenance hub uses a tab-based interface with the following pattern:

  • Each tab is identified by a data-tab attribute in the HTML
  • A switchTab(tabName) JavaScript function handles visibility toggling
  • The tasks table is rendered inside the systems tab (not a dedicated "tasks" tab)
  • Tab switching works via CSS classes: the active tab receives a visible state; others are hidden

This is a common pattern for dashboard applications and keeps the logic simple and performant. By triggering `switchTab('systems')` from the card click handler, we reuse existing infrastructure rather than adding new navigation logic.

CSS and Interactivity Changes

The original Total Tasks card was a static div with the class info-card. To make it clickable, we:

  1. Wrapped the card content to ensure the entire card is a click target
  2. Added an onclick="switchTab('systems')" handler
  3. Created a new CSS class info-card-link to provide visual feedback:
    • cursor: pointer — signals interactivity to users
    • transition — smooth hover effects
    • :hover state — subtle shadow or scale change to confirm responsiveness

The CSS addition is minimal but critical for UX:

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

.info-card-link:hover {
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  transform: translateY(-2px);
}

This creates a subtle lift effect on hover, which is a well-established affordance pattern that signals clickability without being obtrusive.

Infrastructure and Deployment

S3 and CloudFront Coordination

The maintenance hub is hosted on S3 with CloudFront as the content delivery and caching layer. The deployment process involves two critical steps:

  1. Upload to S3: The updated index.html is pushed to the origin bucket using the AWS CLI or SDK
  2. Invalidate CloudFront: A cache invalidation is issued to ensure edge locations serve the new version immediately

Without the invalidation step, users would see the old cached version for up to 24 hours (depending on CloudFront's TTL settings). The invalidation command:

aws cloudfront create-invalidation \
  --distribution-id [DISTRIBUTION_ID] \
  --paths "/*"

This clears all cached objects, forcing edge locations to fetch the latest version from S3 on the next request. For a production dashboard, a more granular path pattern (e.g., `/index.html`) is often preferred to reduce costs, but full invalidation is appropriate for rapid iteration.

Why This Architecture?

Hosting the dashboard frontend in S3 + CloudFront rather than as part of the main site offers several advantages:

  • Decoupled deployments: Dashboard updates don't require rebuilding or redeploying the entire site
  • High availability: CloudFront's global edge network ensures low latency regardless of user location
  • Cost efficiency: S3 + CloudFront is significantly cheaper than running a dedicated web server for static assets
  • Scalability: No application server load; the dashboard handles traffic spikes via CDN caching

This approach is especially valuable for JADA's use case, where the dashboard is accessed from a boat with intermittent connectivity. CloudFront's edge caching means even if the origin S3 bucket is temporarily unreachable, recently-cached versions remain available.

Key Decisions and Rationale

Why Wrap the Card Rather Than Add a Link

We could have converted the card to an <a> tag or used a button element, but we chose to add onclick to the existing div and apply pointer cursor via CSS. Here's why:

  • Preserves existing styling: The card's layout, padding, and visual hierarchy remain unchanged
  • Maintains semantic clarity: The card is still a card (not reframed as a link), which is more accurate for screen readers and semantic HTML
  • Allows flexible event handling: JavaScript gives us fine-grained control; we can log analytics, validate state, or trigger animations before switching tabs
  • Follows the site's existing pattern: The maintenance hub already uses JavaScript-driven navigation rather than hyperlinks

Why CSS Hover Effects Matter

The hover state is not cosmetic—it's a critical affordance. Users need clear feedback that an element is interactive. The subtle lift (shadow + translate