Environment Badge — Free HTML CSS JS DEV/STAGING/PROD Ribbon Snippet

Environment Badge · Buttons · Plain HTML, CSS & JS · Live preview

CategoryButtons

What's included

Features

Diagonal corner ribbon from a single rotated div with a fixed width — long labels like PRODUCTION never clip
One --env CSS variable per environment colors the ribbon, the page top edge and the chip dot
detectEnv() maps localhost, staging/stg/qa/preview and production hostnames, with a ?env= override
Tab title prefix ([STG]) and a canvas-drawn colored favicon make the wrong tab easy to spot
Build chip shows branch, commit and build number, with one-click Copy for bug reports
Optional hide-in-production switch in a single line
pointer-events: none so the ribbon never blocks clicks underneath
Accessible: role="status" with an aria-label announcing the environment, and aria-pressed on the switcher
Easily extended with new environments: one CSS block and one ENVS entry

About this UI Snippet

Environment Badge — Corner Ribbon, Favicon and Build Info for Dev, Staging and Prod

Screenshot of the Environment Badge snippet rendered live

Internal tools that talk to real customer data are dangerous to confuse with a staging or dev copy — one wrong click in the wrong environment can send a real email, refund a real order, or delete real rows. This snippet is a small but high-value safety net: a diagonal corner ribbon, color-coded by environment, plus the extras developers actually want — hostname auto-detection, a colored favicon and tab title, and a one-click "copy build info" chip for bug reports.

How the diagonal ribbon is built

The badge is a single div with position: absolute inside a position: relative; overflow: hidden container (your app shell, in a real integration). It has a fixed width, centered text and transform: rotate(45deg), and sits at top: 24px; right: -46px. Because the width is fixed rather than driven by padding, the label is never clipped — "PRODUCTION" fits as comfortably as "DEV". pointer-events: none means the ribbon never steals a click from whatever is underneath it.

One CSS variable per environment

The container carries data-env="dev|staging|prod", and three tiny rules set --env (the color) and --env-ink (readable text color on top of it). The ribbon background, the 3px top edge of the page and the chip dot all read var(--env), so adding an environment is one CSS block and one entry in the ENVS object.

Detecting the environment automatically

detectEnv() maps the hostname to an environment: localhost, 127.x and *.local are dev; hosts containing staging, stg, qa or preview are staging; everything else is production. A ?env=staging query parameter overrides it for quick testing. In a real app, replace the demo's setEnv('dev') with setEnv(detectEnv()), or pass a value from a build-time variable such as process.env.NEXT_PUBLIC_ENV.

Beyond the ribbon: tab title, favicon and build info

setEnv() also prefixes the document title ([STG] Internal Admin Tool) and redraws the favicon as a dot in the environment color, so you can spot the wrong tab in a crowd of twelve. The build chip shows environment, branch, short commit and build number, and its Copy button puts a single line (env=staging branch=... commit=... build=... region=... host=...) on the clipboard — paste it straight into a bug report or Slack thread.

Show it in production?

Some teams render a badge in production so the *absence* of a dev/staging color is never an assumption; others render nothing at all. The "Show badge in production" checkbox shows the one-line switch: badge.hidden = env === 'prod' && !showProd.checked.

Step by step

How to Use

  1. 1
    Load the snippetClick "Environment Badge" in the sidebar Library tab to see the ribbon overlaying the mock app corner.
  2. 2
    Switch environmentsClick DEV, STAGING, or PRODUCTION to change the ribbon, the top edge color, the build chip, the tab title and the favicon together.
  3. 3
    Copy the build infoClick Copy on the chip to put env, branch, commit, build number, region and hostname on your clipboard for a bug report.
  4. 4
    Try hide-in-productionSelect PRODUCTION and untick "Show badge in production" to see the ribbon disappear while the rest keeps working.
  5. 5
    Add or rename environmentsAdd a [data-env="qa"] block in CSS that sets --env and --env-ink, then add a matching entry to the ENVS object in the JS panel.
  6. 6
    Wire it to the real environmentReplace setEnv('dev') with setEnv(detectEnv()) and feed the BUILD object from your CI (commit hash, build number, branch).
  7. 7
    Export and saveExport as HTML/JSX/Tailwind or click "Save as" to keep this in your personal snippet library.

Real-world uses

Common Use Cases

ADMIN
Internal admin and ops tools
Prevent costly mistakes by making it visually obvious which environment a support or ops team member is currently working in.
QA and staging review builds
Give QA testers and stakeholders an unmissable visual cue when reviewing a staging deploy versus production.
Multi-tenant or multi-region dashboards
Adapt the same ribbon pattern to flag which tenant, region, or data source a dashboard is currently pointed at.
Learn the CSS diagonal ribbon technique
Study how a fixed-width, rotated, absolutely positioned element inside an overflow-hidden parent produces a clean diagonal banner without an SVG or image.
Environment-aware component libraries
Bundle this badge into a shared internal component library so every project automatically shows its environment.
Related: Connection Quality Indicator — Signal Bars from Real Network Signals
See the Connection Quality Indicator — Signal Bars from Real Network Signals for a related misc pattern worth pairing with this one.
Related: Product Image Magnify Lens
See the Product Image Magnify Lens for a related misc pattern worth pairing with this one.
Related: Text Case Converter
See the Text Case Converter for a related misc pattern worth pairing with this one.
Related: Unit Price / Best Value Calculator
See the Unit Price / Best Value Calculator for a related misc pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

A diagonal ribbon in the exact corner draws the eye without stealing significant screen real estate or covering important UI, while still being large and bold enough to notice immediately.

A plain div with a fixed width and centered text is positioned near the top-right corner and rotated 45 degrees with a CSS transform. The parent has overflow: hidden, which trims the band to a clean corner ribbon.

detectEnv() checks location.hostname: localhost, 127.x and *.local are dev, hostnames containing staging, stg, qa or preview are staging, and anything else is production. Adjust the two regular expressions to match your own domains, or pass a build-time environment variable instead.

Some teams do, so the badge state is always explicit rather than assumed. Others render nothing in production — set badge.hidden when env is "prod", as the checkbox in this demo does.

Developers keep many tabs open, and the corner ribbon is invisible on a background tab. A colored favicon dot and a [STG] title prefix make the wrong environment obvious from the tab strip alone.

Inject them at build time from your CI, for example the output of git rev-parse --short HEAD and your pipeline's build number, into a BUILD constant or public environment variables. The demo hard-codes sample values.

Yes — add a [data-env="qa"] CSS block that sets --env and --env-ink, and add a matching entry to the ENVS object in the JavaScript.

No. The ribbon has pointer-events: none, so clicks pass straight through to whatever is under it.

No — it is absolutely positioned and has no impact on the flow of surrounding content. It only requires the parent container to have position: relative (or fixed, for a viewport-anchored version).

Build with AI

Build, Understand, Optimize, and Extend It With AI

Ask an AI assistant to adapt the badge to your stack: have it write the detectEnv() hostname rules for your real domains, wire BUILD to your CI (GitHub Actions, GitLab CI or Vercel system variables), or turn the ribbon into a React or Vue component. It's also a good prompt for extending the idea — for example a QA environment, a region or tenant indicator, or a badge that warns when the page is pointed at a production API from a non-production host.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build an "environment badge" for flagging non-production builds of an internal tool, in plain HTML, CSS and JavaScript.

Requirements:
- A diagonal corner ribbon: one absolutely positioned div with a fixed width and centered text, rotated 45 degrees in the top-right corner of a relatively positioned, overflow-hidden container. Labels like PRODUCTION must never clip. pointer-events: none.
- Three environments (DEV amber, STAGING indigo, PRODUCTION red) driven by a data-env attribute that sets --env and --env-ink CSS variables; the ribbon background, a 3px top edge on the page and a status dot all use var(--env).
- A config object ENVS (label and short code per environment) and a detectEnv() function that reads location.hostname (localhost/127.x/*.local = dev; staging|stg|qa|preview = staging; else prod) with a ?env= query override.
- setEnv(name) updates the data attribute, label, aria-label, document.title prefix such as [STG] (none in prod), and a canvas-drawn favicon in the environment color.
- A build info chip showing environment, branch, short commit and build number from a BUILD constant, with a Copy button that writes one line (env, branch, commit, build, region, host) to the clipboard and handles failure.
- A "show badge in production" option that sets badge.hidden.
- Demo buttons to preview all three states, with a comment that a real app should call setEnv(detectEnv()) once at startup.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Source Code

<div class="demo-page" id="app" data-env="dev">
  <div class="env-badge" id="envBadge" role="status"><span id="envLabel">DEV</span></div>
  <div class="app-mock">
    <h3>Internal Admin Tool</h3>
    <p>This ribbon sits fixed in the corner of every non-production build so nobody mistakes a staging session for live data.</p>
    <div class="build-chip">
      <span class="chip-dot"></span>
      <code id="buildInfo"></code>
      <button type="button" id="copyBuild" aria-label="Copy build info for a bug report">Copy</button>
    </div>
  </div>
</div>
<div class="switcher" id="switcher">
  <button type="button" data-env="dev">DEV</button>
  <button type="button" data-env="staging">STAGING</button>
  <button type="button" data-env="prod">PRODUCTION</button>
</div>
<label class="opt"><input type="checkbox" id="showProd" checked> Show badge in production</label>