Skip to content

Instantly share code, notes, and snippets.

@Potherca
Last active February 18, 2024 20:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Potherca/4a2b95623519e74b63d9485a4311ac3c to your computer and use it in GitHub Desktop.
Save Potherca/4a2b95623519e74b63d9485a4311ac3c to your computer and use it in GitHub Desktop.
🟨🩳 JS shorts Generate UUIDv4 https://gist.pother.ca/4a2b95623519e74b63d9485a4311ac3c

Creating a real UUIDv4 in JS usually requires a library. The new https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID can be used in the browser.

But how hard is it to create a valid UUIDv4? As it turns out, not very!

The following is all that is needed for a version 4 UUID (including correctly setting the so called M and N bits):

const generateUUID = () => "10000000-1000-4000-8000-100000000000".replace(/[018]/g, s => (s ^ Math.random() * 256 & 15 >> s / 4).toString(16));

This can be seen in action at https://gist.pother.ca/4a2b95623519e74b63d9485a4311ac3c

function generateUUID() {
return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, s => (s ^ Math.random() * 256 & 15 >> s / 4).toString(16));
}
<!doctype html>
<html lang="en">
<meta charset="UTF-8">
<title>Generate UUIDv4</title>
<link rel="icon" href="https://favicon.potherca.workers.dev/33" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/picnic">
<link rel="stylesheet" href="https://pother.ca/CssBase/css/created-by-potherca.css">
<link rel="stylesheet" href="https://gist.pother.ca/33b4d10024f56ba0610f8e70477687cb/copy-button.css">
<script async src="https://gist.pother.ca/33b4d10024f56ba0610f8e70477687cb/copy-button.js"></script>
<style>
article {
background-color: #fff;
border-bottom-left-radius: 0.5em;
border-bottom-right-radius: 0.5em;
}
body {
background-color: #def;
}
.created-by {
padding: 0.5em;
text-align: center;
width: 100%;
}
.hidden {
visibility: hidden;
}
.button[data-tooltip] {
border-radius: 100%;
flex: 0 1 auto;
font-size: 0.85em;
height: 2em;
line-height: 2em;
margin-top: 0.85em;
padding: 0;
text-align: center;
width: 2em;
}
button[type="submit"] {
min-width: 10em;
margin-right: 0.6em;
}
.button.pseudo {
display: block;
padding: 0.4em;
border: 1px solid #ddd;
}
pre {
display: block;
font-family: monospace;
margin: 0.5em;
padding: 0.5em;
text-align: center;
white-space: pre-wrap;
word-break: break-all;
}
li p {
border: none;
display: block;
font-family: monospace;
font-size: 1.2em;
text-align: center;
}
li p span {
min-width: 10em;
display: inline-block;
}
.flex label {
padding-bottom: 0;
padding-left: 0;
margin-right: 0.6em;
}
li {
margin: 0.5em;
}
li:nth-child(2) {opacity: 0.8;}
li:nth-child(3) {opacity: 0.7;}
li:nth-child(4) {opacity: 0.6;}
li:nth-child(5) {opacity: 0.5;}
li:nth-child(6) {opacity: 0.4;}
li:nth-child(7) {opacity: 0.3;}
li:nth-child(8) {opacity: 0.2;}
li:nth-child(9) {opacity: 0.1;}
/* everything beyond 9th child shoudl display none */
li:nth-child(n+10) {
display: none;
}
ul {
list-style: none;
padding: 0;
}
.short {
visibility: hidden;
color: #999;
white-space: nowrap;
}
.show-short .short {
visibility: visible;
}
</style>
<article class="flex two-third-500 off-sixth-500">
<header class="full">
<h1>Generate an UUIDv4</h1>
</header>
<main class="full">
<form class="flex full">
<button class="half" type="submit">Generate UUID</button>
<label class="hidden">
<input type="checkbox">
<span class="toggle button pseudo">RFC 4648 Base64url</span>
</label>
<a data-tooltip="Visit RFC 4648" class="button tooltip-top hidden" href="https://datatracker.ietf.org/doc/html/rfc4648#section-5" target="_blank" rel="noopener noreferrer">?</a>
</form>
<ul class="full">
</ul>
</main>
</article>
<footer class="created-by">
<p>
Source of this page is
available on <a href="https://gist.github.com/Potherca/4a2b95623519e74b63d9485a4311ac3c">Github</a>
under a <a rel="license" href="https://spdx.org/licenses/MPL-2.0.html"
>Mozilla Public License 2.0</a> &mdash; Created by <a href="https://pother.ca/" class="potherca">Potherca</a>
</p>
</footer>
<pre data-js="copy">const generateUUID = () => "10000000-1000-4000-8000-100000000000".replace(/[018]/g, s => (s ^ Math.random() * 256 & 15 >> s / 4).toString(16));</pre>
<script>
const generateUUID = () => "10000000-1000-4000-8000-100000000000".replace(/[018]/g, s => (s ^ Math.random() * 256 & 15 >> s / 4).toString(16));
function uuidToBinary(uuid) {
const binary = uuid
.replaceAll('-', '')
.split('')
.map(character => parseInt(character, 16).toString(2).padStart(4, '0'))
.join('')
return binary;
}
const uuidToChars = (uuid) => {
const chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_'.split('')
const binary = uuidToBinary(uuid);
return binary
.split(new RegExp(`(.{1,6})`))
.filter(Boolean)
.map(binary => chars[parseInt(binary, 2)]).join('')
}
const form = document.querySelector("form");
const list = document.querySelector("ul");
const shorter = form.querySelector('[type="checkbox"]');
shorter.addEventListener('change', () => list.classList.toggle('show-short'));
form.addEventListener('submit', (event) => {
event.preventDefault();
let uuid = generateUUID();
list.insertAdjacentHTML('afterbegin', `
<li>
<p class="full">
<span>${uuid}</span>
<span class="short">${uuidToChars(uuid)}</span>
</p>
</li>
`);
document.querySelectorAll('label, [data-tooltip]').forEach(element => element.classList.remove('hidden'));
});
</script>
function uuidToBinary(uuid) {
return uuid
.replaceAll('-', '')
.split('')
.map(character => parseInt(character, 16).toString(2).padStart(4, '0'))
.join('')
}
function uuidToChars(uuid) {
// "URL and Filename safe" Base 64 Alphabet https://www.rfc-editor.org/rfc/rfc4648#section-5
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'.split('')
const binary = uuidToBinary(uuid);
return binary
.split(new RegExp(`(.{1,6})`))
.filter(Boolean)
.map(binary => chars[parseInt(binary, 2)]).join('')
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment