webdevpuneet.com

Credential Expiry Warning Card — Color-Escalating API Key / Certificate Countdown

Credential Expiry Warning Card — Color-Escalating Countdown · Cards · Plain HTML, CSS & JS · Live preview

CategoryCards

Copy & paste

Source Code

<div class="demo" id="demo"></div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month, 7 days free), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Single ordered tier-classification function drives every visual signal — border color, icon, message tone, and button label — for a given credential
Most-urgent-first threshold checking correctly prevents an already-expired credential from being mis-classified into a less urgent tier
Human-readable expiry wording (including a correct negative-days "expired X days ago" case) is a separate concern from tier classification
Threshold values (what counts as critical vs warning) live in exactly one place, with every visual consequence following automatically from a single change
Action button label itself escalates with severity ("Manage" through "Rotate now"), reinforcing urgency beyond just color
Generic rendering from a plain data array — adding new credentials requires no new classification or styling logic
Singular/plural day-count wording handled correctly ("Expires tomorrow" vs "Expires in 9 days" vs "Expired 1 day ago")

About this UI Snippet

Credential Expiry Warning Cards — One Classification, Every Visual Signal

Screenshot of the Credential Expiry Warning Card — Color-Escalating Countdown snippet rendered live

Expired API keys, lapsed SSL certificates, and stale service tokens cause real production incidents, and they usually fail silently until the moment something breaks. A warning card that surfaces "how much time is left" clearly — and escalates its visual urgency correctly as that time shrinks — is a small UI investment against a genuinely costly failure mode. The key implementation detail: every visual signal for a given credential must be derived from the *same* classification, or the card risks showing conflicting severity cues.

One ordered tier list, checked most-urgent-first

classify() checks a credential's daysRemaining against thresholds in a specific order — expired (≤0 days) first, then critical (≤3 days), then warning (≤14 days), falling through to a calm default otherwise. This ordering isn't arbitrary: if the checks ran in the opposite order (warning first), a credential that's actually *already expired* (a negative number) would incorrectly satisfy the "≤14 days" warning check before ever reaching the "≤0" expired check, since a negative number is also less than 14. Checking most-urgent-first and returning immediately on the first match is what guarantees a genuinely overdue credential can never be mis-classified as merely "warning" tier.

Every visual element reads from the same tier object

The returned tier object carries a CSS class name, an icon, and an action-button label all together, as one unit — the card's border color, background tint, icon, and button text are all derived from this single object in one render pass, rather than four separate conditional checks scattered through the markup that could each independently drift out of sync with the others. If a card is styled with the "critical" red border, its icon, message tone, and button label are *guaranteed* to also reflect critical — there's no code path where one signal updates without the others.

Human-readable detail text is a separate concern from tier classification

formatDetail() handles the *wording* ("Expires in 9 days" vs "Expired 3 days ago" vs "Expires tomorrow") entirely independently of classify(), which only handles *which tier applies*. Keeping these separate means the exact day-count thresholds for changing color can be tuned without touching the wording logic, and the wording logic (singular vs plural "days", the "tomorrow" special case) can be refined without touching threshold values — two genuinely distinct concerns, kept as two distinct functions.

Threshold values live in exactly one place

The specific cutoffs (0, 3, 14 days) appear in classify()'s conditionals and nowhere else — there's no duplicated "is this expiring soon" check anywhere else in the rendering logic that could independently drift to a different threshold over time. Changing what counts as "critical" requires editing one number in one function, with every visual consequence of that change following automatically.

Step by step

How to Use

  1. 1
    Review the credential listEach row shows a name, a human-readable expiry detail, and a color-coded card matching its urgency tier — calm, warning (amber), critical (red), or expired (dark red).
  2. 2
    Notice the already-expired entryThe S3 access key shows a dark "expired" state with a negative-day count correctly converted into "Expired 3 days ago" rather than a confusing negative number.
  3. 3
    Click "Rotate now" or "Rotate soon"Confirms the action in this demo — in a real implementation this would trigger an actual credential rotation flow.
  4. 4
    Adjust the CREDENTIALS arrayAdd your own credentials with a name and daysRemaining value — classify() and formatDetail() handle rendering generically.
  5. 5
    Tune the tier thresholdsChange the day-count cutoffs inside classify() (currently 0, 3, and 14) to match your own organization's rotation policy.

Real-world uses

Common Use Cases

DEVOPS
API key and secret rotation dashboards
Internal tools tracking API keys, service tokens, and secrets that need periodic manual or automated rotation before expiry.
SECURITY
SSL/TLS certificate expiry tracking
Certificate management tools where a lapsed cert can cause a real production outage, needing clear escalating urgency well before expiry.
ADMIN
Admin panel security/compliance widgets
Compliance-focused admin dashboards surfacing any credential, permission grant, or access token nearing its expiry.
DEVTOOLS
Developer portal credential management
Self-service developer portals where users manage their own API keys and need clear, unmistakable expiry warnings.
Related: Image Hover Reveal Cards
See the Image Hover Reveal Cards for a related cards pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

Because a negative daysRemaining value (already expired) also technically satisfies a "less than or equal to 3" critical check. Checking the most urgent tier (expired) FIRST and returning immediately on a match guarantees an overdue credential is correctly classified as expired, not accidentally caught by a less urgent, more loosely matching threshold checked earlier.

No — both are read from the exact same tier object returned by a single call to classify(), applied together in one render pass. There is no separate, independently-maintained conditional for the icon versus the border color that could drift out of sync with each other.

formatDetail() explicitly checks for daysRemaining <= 0 and formats it as "Expired X days ago" (using the absolute value and correct singular/plural wording), rather than displaying a confusing raw negative number like "Expires in -3 days."

Edit the threshold numbers directly inside classify() — currently 3 days for critical and 14 days for warning. Because every visual signal is derived from this one function's output, changing these numbers automatically and correctly updates the color, icon, and button label behavior for every credential without touching any other code.

No — formatDetail() and classify() are deliberately separate functions. classify() only determines which urgency tier applies; formatDetail() only determines how to word the specific day count. This separation lets you refine either concern independently without affecting the other.

In this demo, it disables itself and shows a confirmation label — in a real implementation, you'd replace that handler with an actual credential rotation request, likely followed by re-fetching or updating the credential's daysRemaining value once rotation completes.