Free Password Generator Widget
Let visitors create strong, random passwords right on your site.
A lightweight password generator with a length slider, character-set toggles for uppercase, lowercase, digits, and symbols, plus a live entropy strength meter and one-click copy. It is great for SaaS tools, security blogs, and IT or developer sites that want a handy utility their audience will actually use. Install it with a single script tag — passwords are generated locally in the browser, nothing leaves the page.
Embed this widget
Paste either snippet into your page — a Custom HTML block on WordPress, Shopify, or Squarespace works too. Both snippets update live as you customize, so what you copy is exactly what you configured.
<script src="https://hayneslab.dev/widgets/password-generator.js" async></script>
<!-- Free Password Generator widget by haynes lab — https://hayneslab.dev/tools/widgets/password-generator --><!-- Free Password Generator widget by haynes lab — https://hayneslab.dev/tools/widgets/password-generator -->
<script>
/*!
* haynes lab — Password Generator widget (free)
* Docs & embed code: https://hayneslab.dev/tools/widgets/password-generator
*/
(function () {
'use strict';
var PREFIX = 'hlw-password-generator';
var STYLE_ID = 'hlw-password-generator-styles';
var SET_DEFS = [
{ key: 'upper', label: 'ABC', name: 'Uppercase letters', chars: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' },
{ key: 'lower', label: 'abc', name: 'Lowercase letters', chars: 'abcdefghijklmnopqrstuvwxyz' },
{ key: 'digits', label: '123', name: 'Digits', chars: '0123456789' },
{ key: 'symbols', label: '#$&', name: 'Symbols', chars: '!@#$%^&*()-_=+[]{};:,.<>?/~' }
];
function findScript() {
return document.currentScript ||
document.querySelector('script[src*="widgets/password-generator.js"]');
}
function injectStyles() {
if (document.getElementById(STYLE_ID)) return;
var css =
'.' + PREFIX + ', .' + PREFIX + ' * { box-sizing: border-box; }' +
'.' + PREFIX + ' { position: relative; max-width: 480px; margin: 0 auto; padding: 24px 24px 32px;' +
' font-family: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;' +
' font-size: 16px; line-height: 1.5; color: #1f2937; background: #ffffff;' +
' border: 1px solid #e5e7eb; border-radius: 12px; }' +
'.' + PREFIX + '__title { margin: 0 0 14px; font-size: 18px; font-weight: 600; color: #111827; }' +
'.' + PREFIX + '__output { display: flex; gap: 8px; margin-bottom: 16px; }' +
'.' + PREFIX + '__field { flex: 1; min-width: 0; padding: 10px 12px; font-size: 15px;' +
' font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; color: #111827;' +
' background: #f9fafb; border: 1px solid #e5e7eb; border-radius: 8px; }' +
'.' + PREFIX + '__copy { flex: 0 0 auto; padding: 10px 14px; font-size: 14px; font-weight: 600;' +
' color: #ffffff; background: var(--hlw-accent); border: 0; border-radius: 8px; cursor: pointer; }' +
'.' + PREFIX + '__copy:hover { filter: brightness(0.92); }' +
'.' + PREFIX + '__copy:focus-visible { outline: 2px solid var(--hlw-accent); outline-offset: 2px; }' +
'.' + PREFIX + '__row { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; }' +
'.' + PREFIX + '__lenlabel { font-size: 14px; color: #374151; white-space: nowrap; }' +
'.' + PREFIX + '__lenval { font-weight: 600; color: #111827; min-width: 2ch; text-align: right; }' +
'.' + PREFIX + '__range { flex: 1; accent-color: var(--hlw-accent); }' +
'.' + PREFIX + '__toggles { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 16px; }' +
'.' + PREFIX + '__toggle { display: inline-flex; align-items: center; gap: 6px; padding: 7px 12px;' +
' font-size: 13px; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;' +
' color: #374151; background: #f9fafb; border: 1px solid #e5e7eb; border-radius: 999px;' +
' cursor: pointer; }' +
'.' + PREFIX + '__toggle[aria-pressed="true"] { color: var(--hlw-accent);' +
' border-color: var(--hlw-accent); background: #ffffff; }' +
'.' + PREFIX + '__toggle:focus-visible { outline: 2px solid var(--hlw-accent); outline-offset: 2px; }' +
'.' + PREFIX + '__generate { width: 100%; padding: 11px 16px; margin-bottom: 14px; font-size: 15px;' +
' font-weight: 600; color: #ffffff; background: var(--hlw-accent); border: 0;' +
' border-radius: 8px; cursor: pointer; }' +
'.' + PREFIX + '__generate:hover { filter: brightness(0.92); }' +
'.' + PREFIX + '__generate:focus-visible { outline: 2px solid var(--hlw-accent); outline-offset: 2px; }' +
'.' + PREFIX + '__meter { height: 6px; background: #e5e7eb; border-radius: 999px; overflow: hidden;' +
' margin-bottom: 6px; }' +
'.' + PREFIX + '__meterfill { height: 100%; width: 0; border-radius: 999px;' +
' transition: width 0.25s ease, background-color 0.25s ease; }' +
'.' + PREFIX + '__meterlabel { font-size: 12px; color: #6b7280; }' +
'.' + PREFIX + '__credit { position: absolute; right: 10px; bottom: 6px; font-size: 11px;' +
' display: inline-flex; align-items: center; gap: 4px; color: #9ca3af; text-decoration: none; }' +
'.' + PREFIX + '__credit svg { display: block; }' +
'.' + PREFIX + '__credit:hover { color: #6b7280; text-decoration: underline; }' +
'@media (max-width: 560px) { .' + PREFIX + ' { padding: 18px 16px 32px; } }';
var style = document.createElement('style');
style.id = STYLE_ID;
style.textContent = css;
document.head.appendChild(style);
}
function el(tag, className, text) {
var node = document.createElement(tag);
if (className) node.className = className;
if (text != null) node.textContent = text;
return node;
}
function logoSvg() {
var svgNS = 'http://www.w3.org/2000/svg';
var svg = document.createElementNS(svgNS, 'svg');
svg.setAttribute('viewBox', '0 0 32 32');
svg.setAttribute('width', '13');
svg.setAttribute('height', '13');
svg.setAttribute('aria-hidden', 'true');
svg.setAttribute('focusable', 'false');
function circle(cx, cy, r, attrs) {
var c = document.createElementNS(svgNS, 'circle');
c.setAttribute('cx', cx);
c.setAttribute('cy', cy);
c.setAttribute('r', r);
for (var key in attrs) c.setAttribute(key, attrs[key]);
svg.appendChild(c);
}
circle(16, 16, 16, { fill: '#0f0a0a' });
circle(16, 16, 12, { fill: 'none', stroke: '#fff5f5', 'stroke-width': 1, opacity: 0.3 });
circle(16, 16, 9, { fill: 'none', stroke: '#fff5f5', 'stroke-width': 1, opacity: 0.5 });
circle(16, 16, 6, { fill: 'none', stroke: '#fff5f5', 'stroke-width': 1.2, opacity: 0.9 });
circle(16, 16, 3, { fill: '#06b6d4' });
circle(24.5, 7.5, 2, { fill: '#f97316' });
circle(7, 16, 1.8, { fill: '#f97316' });
circle(20, 20, 1.5, { fill: '#f97316' });
return svg;
}
function randomIndex(max) {
if (window.crypto && window.crypto.getRandomValues) {
var buf = new Uint32Array(1);
window.crypto.getRandomValues(buf);
return buf[0] % max;
}
return Math.floor(Math.random() * max);
}
function build(script) {
var length = parseInt(script.getAttribute('data-hl-length'), 10);
if (isNaN(length) || length < 4) length = 16;
if (length > 64) length = 64;
var accent = script.getAttribute('data-hl-accent') || '#f97316';
injectStyles();
var root = el('div', PREFIX);
root.setAttribute('role', 'region');
root.setAttribute('aria-label', 'Password generator');
root.style.setProperty('--hlw-accent', accent);
root.appendChild(el('h3', PREFIX + '__title', 'Password Generator'));
var output = el('div', PREFIX + '__output');
var field = el('input', PREFIX + '__field');
field.type = 'text';
field.readOnly = true;
field.setAttribute('aria-label', 'Generated password');
var copyBtn = el('button', PREFIX + '__copy', 'Copy');
copyBtn.type = 'button';
output.appendChild(field);
output.appendChild(copyBtn);
root.appendChild(output);
var row = el('div', PREFIX + '__row');
row.appendChild(el('span', PREFIX + '__lenlabel', 'Length'));
var range = el('input', PREFIX + '__range');
range.type = 'range';
range.min = '4';
range.max = '64';
range.value = String(length);
range.setAttribute('aria-label', 'Password length');
var lenVal = el('span', PREFIX + '__lenval', String(length));
row.appendChild(range);
row.appendChild(lenVal);
root.appendChild(row);
var togglesWrap = el('div', PREFIX + '__toggles');
var sets = SET_DEFS.map(function (def, i) {
return { label: def.label, name: def.name, chars: def.chars, on: i < 3 };
});
sets.forEach(function (set) {
var btn = el('button', PREFIX + '__toggle', set.label);
btn.type = 'button';
btn.setAttribute('aria-pressed', set.on ? 'true' : 'false');
btn.setAttribute('aria-label', 'Include ' + set.name);
btn.addEventListener('click', function () {
set.on = !set.on;
btn.setAttribute('aria-pressed', set.on ? 'true' : 'false');
generate();
});
togglesWrap.appendChild(btn);
});
root.appendChild(togglesWrap);
var generateBtn = el('button', PREFIX + '__generate', 'Generate Password');
generateBtn.type = 'button';
root.appendChild(generateBtn);
var meter = el('div', PREFIX + '__meter');
var meterFill = el('div', PREFIX + '__meterfill');
meter.appendChild(meterFill);
root.appendChild(meter);
var meterLabel = el('div', PREFIX + '__meterlabel');
root.appendChild(meterLabel);
function activeSets() {
return sets.filter(function (s) { return s.on; });
}
function updateMeter() {
var len = parseInt(range.value, 10);
var pool = activeSets().reduce(function (n, s) { return n + s.chars.length; }, 0);
var bits = pool ? Math.round(len * Math.log2(pool)) : 0;
var pct = Math.max(0, Math.min(100, (bits / 128) * 100));
var label, color;
if (!pool) { label = 'Select at least one character set'; color = '#9ca3af'; }
else if (bits < 45) { label = 'Weak'; color = '#ef4444'; }
else if (bits < 65) { label = 'Fair'; color = '#f59e0b'; }
else if (bits < 90) { label = 'Strong'; color = '#22c55e'; }
else { label = 'Very strong'; color = '#16a34a'; }
meterFill.style.width = pct + '%';
meterFill.style.backgroundColor = color;
meterLabel.textContent = pool
? label + ' — about ' + bits + ' bits of entropy'
: label;
}
function generate() {
var on = activeSets();
var len = parseInt(range.value, 10);
if (!on.length) { field.value = ''; updateMeter(); return; }
var pool = on.map(function (s) { return s.chars; }).join('');
var pw = '';
for (var i = 0; i < len; i++) pw += pool.charAt(randomIndex(pool.length));
field.value = pw;
copyBtn.textContent = 'Copy';
updateMeter();
}
range.addEventListener('input', function () {
lenVal.textContent = range.value;
generate();
});
generateBtn.addEventListener('click', generate);
copyBtn.addEventListener('click', function () {
if (!field.value) return;
function done() { copyBtn.textContent = 'Copied!'; }
function fallback() {
field.select();
try { document.execCommand('copy'); done(); } catch (e) { field.focus(); }
}
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(field.value).then(done, fallback);
} else {
fallback();
}
});
var credit = el('a', PREFIX + '__credit');
credit.appendChild(logoSvg());
credit.appendChild(document.createTextNode('Powered by haynes lab'));
credit.href = 'https://hayneslab.dev/tools/widgets/password-generator';
credit.target = '_blank';
credit.rel = 'noopener';
root.appendChild(credit);
if (script.parentNode && script.parentNode.nodeName !== 'HEAD') {
script.insertAdjacentElement('afterend', root);
} else {
document.body.appendChild(root);
}
generate();
}
function init() {
var script = findScript();
if (!script) {
console.warn('[haynes lab password-generator] Could not locate its own script tag. Nothing rendered.');
return;
}
build(script);
}
if (document.body) {
init();
} else {
document.addEventListener('DOMContentLoaded', init);
}
})();
</script>Configuration
Every option is an attribute on the script tag — the same attributes the customizer above exposes. All attributes are optional unless marked required — defaults apply when omitted.
| Attribute | Default | Description |
|---|---|---|
data-hl-length | "16" | Initial password length, clamped between 4 and 64 characters. |
data-hl-accent | "#f97316" | Color for the generate/copy buttons, slider, and active toggles. |
Frequently asked questions
How do I install the Password Generator?
Paste the script snippet where you want the generator to appear — it renders inline right after the tag and creates a first password automatically.
Can I change the default length and colors?
Yes — set data-hl-length for the starting password length (4–64) and data-hl-accent for the highlight color on buttons, the slider, and active toggles.
Does it work on WordPress, Shopify, or Squarespace?
Yes — it is a single vanilla JS file with no dependencies, so it works on WordPress, Shopify, Squarespace, or any site that can embed a script tag.
More free widgets
Word Counter
Live word, character, sentence, and reading-time counts as visitors type.
View toolCalculators & UtilitiesUnit Converter
Let visitors convert length, weight, temperature, and volume on your site.
View toolCalculators & UtilitiesPercentage Calculator
Three everyday percentage calculators in one clean embeddable widget.
View toolNeed a custom widget?
We build custom widgets, integrations, and whole products. Tell us what your site needs and we'll scope it.
Get in Touch