Bootstrap Environment Variable Viewer — Free HTML CSS JS Snippet
Bootstrap Environment Variable Viewer · Dashboards · Plain HTML, CSS & JS · Live preview
Copy & paste
Source Code
<div class="container py-5 d-flex justify-content-center">
<div class="card bsenv-card">
<div class="card-body p-3">
<div class="d-flex justify-content-between align-items-center mb-2">
<h6 class="fw-bold mb-0">Environment variables</h6>
<span class="badge text-bg-secondary">production</span>
</div>
<ul class="list-unstyled mb-0" id="bsenvList"></ul>
</div>
</div>
</div>.bsenv-card { width: 440px; max-width: 100%; border: 1px solid #eceef1; border-radius: 14px; }
.bsenv-row { padding: 7px 0; border-bottom: 1px solid #f1f2f5; }
.bsenv-row:last-child { border-bottom: none; }
.bsenv-key { font: 700 12px ui-monospace, Menlo, Consolas, monospace; color: #374151; }
.bsenv-line { display: flex; align-items: center; gap: 8px; }
.bsenv-value { font: 12px ui-monospace, Menlo, Consolas, monospace; color: #6b7280; flex-grow: 1; word-break: break-all; }
.bsenv-toggle, .bsenv-copy { border: none; background: none; color: #9ca3af; cursor: pointer; font-size: 11px; flex-shrink: 0; }
.bsenv-toggle:hover, .bsenv-copy:hover { color: #6366f1; }const VARS = [
{ key: 'NODE_ENV', value: 'production', secret: false },
{ key: 'DATABASE_URL', value: 'postgres://admin:[email protected]:5432/app', secret: true },
{ key: 'STRIPE_SECRET_KEY', value: 'sk_live_51H8x2FaK3n0tR3alKey987ab', secret: true },
{ key: 'PUBLIC_API_URL', value: 'https://api.example.com/v1', secret: false },
{ key: 'JWT_SIGNING_SECRET', value: 'p9Q7wZrT1mXaB4vC6nH2sJ8k', secret: true },
];
function mask(value) {
return '\u2022'.repeat(Math.min(value.length, 24));
}
const list = document.getElementById('bsenvList');
let revealed = new Set();
function render() {
list.innerHTML = VARS.map((v, i) => {
const isRevealed = !v.secret || revealed.has(i);
return '<li class="bsenv-row">' +
'<div class="bsenv-key">' + v.key + '</div>' +
'<div class="bsenv-line">' +
'<span class="bsenv-value">' + (isRevealed ? v.value : mask(v.value)) + '</span>' +
(v.secret ? '<button type="button" class="bsenv-toggle" data-action="toggle" data-index="' + i + '">' + (isRevealed ? 'Hide' : 'Reveal') + '</button>' : '') +
'<button type="button" class="bsenv-copy" data-action="copy" data-index="' + i + '">Copy</button>' +
'</div>' +
'</li>';
}).join('');
}
list.addEventListener('click', e => {
const btn = e.target.closest('button');
if (!btn) return;
const index = Number(btn.dataset.index);
if (btn.dataset.action === 'toggle') {
if (revealed.has(index)) revealed.delete(index); else revealed.add(index);
render();
} else if (btn.dataset.action === 'copy') {
navigator.clipboard.writeText(VARS[index].value).then(() => {
const original = btn.textContent;
btn.textContent = 'Copied';
setTimeout(() => { btn.textContent = original; }, 1200);
});
}
});
render();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.
What's included
Features
About this UI Snippet
Bootstrap Environment Variable Viewer — HTML, CSS & JavaScript

Each variable carries its own secret boolean, and that's what decides two things independently: whether a Reveal/Hide toggle exists for it at all, and whether its value starts masked. A non-secret variable like NODE_ENV never gets a Reveal button in the first place — there's nothing sensitive to hide, so offering a toggle that does nothing meaningful would just be clutter.
Which secrets are currently revealed lives in one revealed Set holding row indices, checked per row with revealed.has(i) — toggling one variable's visibility only ever adds or removes its own index, leaving every other secret's masked/revealed state completely untouched, unlike a single shared "show secrets" boolean that would reveal or hide everything at once.
mask() renders a bullet character repeated up to the real value's length (capped at 24) rather than a fixed-width placeholder — a short value and a long one look visibly different even while both are hidden, giving a rough sense of scale without leaking the actual content. Copy always copies the real, unmasked value regardless of whether it's currently visible on screen, since the whole point of a Copy button next to a secret is to get the real value into a paste target without necessarily displaying it on screen first.
Step by step
How to Use
- 1Load the snippetNODE_ENV and PUBLIC_API_URL show their real values plainly; every other variable shows masked bullets with a Reveal button.
- 2Click "Reveal" next to DATABASE_URLIts real connection string appears, and the button relabels itself "Hide".
- 3Click "Reveal" on a second secret, like STRIPE_SECRET_KEYIt reveals independently — DATABASE_URL stays revealed and unaffected.
- 4Click "Hide" on DATABASE_URLOnly that one value re-masks; STRIPE_SECRET_KEY stays revealed.
- 5Click "Copy" on a still-masked secretThe real value is copied to your clipboard even though it's never been revealed on screen.
Real-world uses
Common Use Cases
Got questions?
Frequently Asked Questions
Only variables marked secret: true render one — a plainly public value like NODE_ENV or an API base URL has nothing to hide, so there's no reveal/hide state relevant to it at all.
No — each secret's visibility is tracked independently by its own index in a Set, so revealing one has zero effect on any other secret's masked or revealed state.
Yes — the Copy button always reads the real value directly from the underlying VARS array, regardless of whether that row is currently showing the masked placeholder or the real text.
Yes. Keep the revealed row indices in a Set (or an equivalent structure) in component state, and derive each row's displayed value and button label from whether its index is present in that state.