Web3 — Address Chip (truncate · copy · ENS)
A reusable wallet identity chip for Web3 interfaces, rendered across every variant you actually ship: a middle-truncated monospace address, an ENS-resolved name with a gradient blockie avatar derived from the address bytes, a copy-on-click chip with clipboard write and a checkmark flip, and a chip that links out to a block explorer. It ships in small, medium, and large densities with online, idle, and offline status dots, plus a hero account card that toggles between raw and resolved display.
MCP
Código
:root {
--bg: #0a0b0f;
--surface: #13151c;
--surface-2: #1b1e27;
--elevated: #23262f;
--text: #e9ecf2;
--muted: #8a90a2;
--line: rgba(255, 255, 255, 0.08);
--line-2: rgba(255, 255, 255, 0.16);
--accent: #7c5cff;
--accent-2: #00e0c6;
--accent-glow: rgba(124, 92, 255, 0.45);
--pos: #26d07c;
--neg: #ff4d6d;
--warn: #ffb347;
--r-sm: 8px;
--r-md: 14px;
--r-lg: 20px;
--r-pill: 999px;
--mono: "JetBrains Mono", ui-monospace, "SFMono-Regular", Menlo, monospace;
--sans: "Space Grotesk", system-ui, -apple-system, sans-serif;
}
* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
margin: 0;
background:
radial-gradient(1100px 600px at 12% -10%, rgba(124, 92, 255, 0.16), transparent 60%),
radial-gradient(900px 500px at 100% 0%, rgba(0, 224, 198, 0.1), transparent 55%),
var(--bg);
color: var(--text);
font-family: var(--sans);
line-height: 1.5;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
min-height: 100vh;
}
.mono { font-family: var(--mono); font-variant-ligatures: none; }
.page {
max-width: 920px;
margin: 0 auto;
padding: 32px 22px 56px;
}
/* ---------- masthead ---------- */
.masthead {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
margin-bottom: 26px;
}
.brand { display: flex; align-items: center; gap: 14px; }
.brand-mark {
width: 40px;
height: 40px;
border-radius: 12px;
background: conic-gradient(from 200deg, var(--accent), var(--accent-2), var(--accent));
box-shadow: 0 0 0 1px var(--line-2), 0 8px 24px var(--accent-glow);
position: relative;
flex: none;
}
.brand-mark::after {
content: "";
position: absolute;
inset: 9px;
border-radius: 6px;
background: var(--bg);
}
.masthead h1 {
margin: 0;
font-size: 1.4rem;
font-weight: 700;
letter-spacing: -0.02em;
}
.sub { margin: 2px 0 0; color: var(--muted); font-size: 0.86rem; }
.net-pill {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 8px 14px;
font-size: 0.8rem;
font-weight: 500;
border-radius: var(--r-pill);
background: rgba(38, 208, 124, 0.08);
border: 1px solid rgba(38, 208, 124, 0.25);
color: var(--text);
backdrop-filter: blur(8px);
white-space: nowrap;
}
.net-pill .dot {
width: 8px; height: 8px; border-radius: 50%;
background: var(--pos);
box-shadow: 0 0 0 3px rgba(38, 208, 124, 0.18);
animation: pulse 2.4s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% { box-shadow: 0 0 0 3px rgba(38, 208, 124, 0.18); }
50% { box-shadow: 0 0 0 6px rgba(38, 208, 124, 0.05); }
}
/* ---------- hero ---------- */
.hero {
position: relative;
border-radius: var(--r-lg);
padding: 1px;
background: linear-gradient(135deg, var(--accent), rgba(0, 224, 198, 0.55) 55%, transparent);
box-shadow: 0 18px 50px rgba(0, 0, 0, 0.45);
margin-bottom: 30px;
}
.hero-inner {
border-radius: calc(var(--r-lg) - 1px);
background:
radial-gradient(600px 240px at 0% 0%, rgba(124, 92, 255, 0.14), transparent 60%),
rgba(19, 21, 28, 0.86);
backdrop-filter: blur(16px);
padding: 22px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 20px;
flex-wrap: wrap;
}
.hero-id { display: flex; align-items: center; gap: 16px; min-width: 0; }
.hero-blockie {
width: 56px; height: 56px;
border-radius: 16px;
box-shadow: 0 0 0 1px var(--line-2), 0 8px 22px rgba(0, 0, 0, 0.45);
flex: none;
}
.hero-meta { min-width: 0; }
.hero-name-row { display: flex; align-items: center; gap: 8px; }
.hero-name {
font-size: 1.32rem;
font-weight: 700;
letter-spacing: -0.02em;
}
.verified {
display: inline-grid; place-items: center;
width: 19px; height: 19px;
border-radius: 50%;
background: var(--accent-2);
color: #04221d;
font-size: 0.7rem; font-weight: 700;
}
.hero-actions { display: flex; gap: 10px; flex-wrap: wrap; }
.ghost-btn {
display: inline-flex;
align-items: center;
gap: 7px;
padding: 9px 14px;
font-family: var(--sans);
font-size: 0.82rem;
font-weight: 500;
color: var(--text);
text-decoration: none;
background: var(--surface-2);
border: 1px solid var(--line);
border-radius: var(--r-pill);
cursor: pointer;
transition: border-color 0.15s, background 0.15s, transform 0.06s;
}
.ghost-btn:hover { border-color: var(--line-2); background: var(--elevated); }
.ghost-btn:active { transform: translateY(1px); }
.ghost-btn[aria-pressed="true"] {
border-color: rgba(124, 92, 255, 0.5);
background: rgba(124, 92, 255, 0.12);
}
/* ---------- chip (core component) ---------- */
.chip {
--chip-pad-y: 8px;
--chip-pad-x: 12px;
--chip-fs: 0.86rem;
--blk: 18px;
display: inline-flex;
align-items: center;
gap: 8px;
padding: var(--chip-pad-y) var(--chip-pad-x);
font-size: var(--chip-fs);
color: var(--text);
text-decoration: none;
background: rgba(27, 30, 39, 0.7);
border: 1px solid var(--line);
border-radius: var(--r-pill);
backdrop-filter: blur(8px);
transition: border-color 0.15s, background 0.15s, transform 0.06s, box-shadow 0.2s;
max-width: 100%;
}
button.chip, a.chip { cursor: pointer; font-family: inherit; }
.chip:hover { border-color: var(--line-2); background: rgba(35, 38, 47, 0.85); }
.chip .addr {
font-weight: 500;
letter-spacing: 0.01em;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.chip-copy:hover { box-shadow: 0 6px 20px rgba(124, 92, 255, 0.18); }
.chip-copy:active, .chip-link:active { transform: translateY(1px); }
.chip-link:hover .link-ic { transform: translate(1px, -1px); }
.chip .link-ic { color: var(--muted); transition: transform 0.15s; }
:where(button, a).chip:focus-visible,
.ghost-btn:focus-visible {
outline: 2px solid var(--accent-2);
outline-offset: 2px;
}
/* blockie avatar — gradient drawn in JS via background */
.blockie {
width: var(--blk);
height: var(--blk);
border-radius: 6px;
flex: none;
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12);
background-size: cover;
}
.chip-sm { --blk: 14px; }
.chip-lg { --blk: 22px; }
/* copy icon flip */
.copy-ic {
position: relative;
width: 15px; height: 15px;
display: inline-grid;
color: var(--muted);
}
.chip-sm .copy-ic { width: 13px; height: 13px; }
.copy-ic svg { grid-area: 1 / 1; transition: opacity 0.2s, transform 0.3s; }
.copy-ic .ic-check { opacity: 0; transform: scale(0.5) rotate(-25deg); color: var(--pos); }
.chip.copied .copy-ic .ic-copy { opacity: 0; transform: scale(0.5) rotate(25deg); }
.chip.copied .copy-ic .ic-check { opacity: 1; transform: none; }
.chip.copied { border-color: rgba(38, 208, 124, 0.5); }
.chip-copy:hover .copy-ic { color: var(--text); }
/* status dot */
.status-dot {
width: 8px; height: 8px;
border-radius: 50%;
flex: none;
margin-left: 2px;
}
.status-dot[data-status="online"] { background: var(--pos); box-shadow: 0 0 0 2px rgba(38, 208, 124, 0.2); }
.status-dot[data-status="idle"] { background: var(--warn); box-shadow: 0 0 0 2px rgba(255, 179, 71, 0.2); }
.status-dot[data-status="offline"] { background: var(--muted); box-shadow: 0 0 0 2px rgba(138, 144, 162, 0.18); }
/* sizes */
.chip-sm { --chip-pad-y: 5px; --chip-pad-x: 9px; --chip-fs: 0.76rem; }
.chip-md { --chip-pad-y: 8px; --chip-pad-x: 12px; --chip-fs: 0.86rem; }
.chip-lg { --chip-pad-y: 11px; --chip-pad-x: 16px; --chip-fs: 0.98rem; }
/* ---------- blocks ---------- */
.block { margin-top: 34px; }
.block-title {
margin: 0;
font-size: 1.05rem;
font-weight: 600;
letter-spacing: -0.01em;
}
.block-note { margin: 4px 0 18px; color: var(--muted); font-size: 0.85rem; }
.grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 14px;
}
.card {
background: rgba(19, 21, 28, 0.7);
border: 1px solid var(--line);
border-radius: var(--r-md);
padding: 16px;
backdrop-filter: blur(10px);
transition: border-color 0.15s, transform 0.12s;
}
.card:hover { border-color: var(--line-2); transform: translateY(-2px); }
.card-h {
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
margin-bottom: 14px;
}
.card-h h3 { margin: 0; font-size: 0.92rem; font-weight: 600; }
.tag {
font-size: 0.66rem;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--muted);
padding: 3px 8px;
border-radius: var(--r-pill);
background: var(--surface-2);
border: 1px solid var(--line);
}
.tag-accent { color: var(--accent-2); border-color: rgba(0, 224, 198, 0.3); background: rgba(0, 224, 198, 0.07); }
.card-body { display: flex; flex-direction: column; align-items: flex-start; gap: 12px; }
.card-cap { margin: 0; color: var(--muted); font-size: 0.78rem; line-height: 1.45; }
/* sizes block */
.size-row {
display: flex;
align-items: flex-end;
gap: 22px;
flex-wrap: wrap;
padding: 6px 2px;
}
.size-cell { display: flex; flex-direction: column; gap: 8px; }
.size-label {
font-size: 0.68rem;
text-transform: uppercase;
letter-spacing: 0.1em;
color: var(--muted);
}
.legend {
display: flex;
gap: 18px;
margin-top: 18px;
font-size: 0.78rem;
color: var(--muted);
}
.legend span { display: inline-flex; align-items: center; gap: 7px; }
.legend .lg { width: 8px; height: 8px; border-radius: 50%; }
.legend .online { background: var(--pos); }
.legend .idle { background: var(--warn); }
.legend .offline { background: var(--muted); }
/* ---------- footer ---------- */
.foot {
margin-top: 40px;
padding-top: 18px;
border-top: 1px solid var(--line);
text-align: center;
}
.foot p { margin: 0; color: var(--muted); font-size: 0.74rem; }
/* ---------- toast ---------- */
.toast-wrap {
position: fixed;
left: 50%;
bottom: 26px;
transform: translateX(-50%);
display: flex;
flex-direction: column;
gap: 10px;
z-index: 50;
pointer-events: none;
width: max-content;
max-width: calc(100vw - 32px);
}
.toast {
display: flex;
align-items: center;
gap: 10px;
padding: 11px 16px;
font-size: 0.84rem;
color: var(--text);
background: rgba(27, 30, 39, 0.92);
border: 1px solid var(--line-2);
border-radius: var(--r-pill);
box-shadow: 0 14px 40px rgba(0, 0, 0, 0.5);
backdrop-filter: blur(14px);
animation: toast-in 0.28s cubic-bezier(0.2, 0.9, 0.3, 1.2);
}
.toast.out { animation: toast-out 0.22s ease forwards; }
.toast .t-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--accent-2); flex: none; }
.toast .t-hash { font-family: var(--mono); color: var(--muted); font-size: 0.78rem; }
@keyframes toast-in { from { opacity: 0; transform: translateY(12px) scale(0.96); } to { opacity: 1; transform: none; } }
@keyframes toast-out { to { opacity: 0; transform: translateY(8px) scale(0.97); } }
/* ---------- responsive ---------- */
@media (max-width: 520px) {
.page { padding: 22px 16px 48px; }
.masthead { flex-direction: column; align-items: flex-start; }
.hero-inner { padding: 18px; }
.hero-id { width: 100%; }
.hero-actions { width: 100%; }
.ghost-btn { flex: 1; justify-content: center; }
.grid { grid-template-columns: 1fr; }
.size-row { gap: 16px; }
.masthead h1 { font-size: 1.25rem; }
}
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}/* Web3 — Address Chip — UI-only simulation. No wallet / RPC / on-chain calls. */
(function () {
"use strict";
/* ---------- tiny deterministic hash for blockies ---------- */
function seedFrom(str) {
let h = 2166136261 >>> 0;
for (let i = 0; i < str.length; i++) {
h ^= str.charCodeAt(i);
h = Math.imul(h, 16777619) >>> 0;
}
return h >>> 0;
}
function mulberry32(a) {
return function () {
a |= 0;
a = (a + 0x6d2b79f5) | 0;
let t = Math.imul(a ^ (a >>> 15), 1 | a);
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
};
}
/* Build a gradient "blockie" purely from the address string. */
function paintBlockie(el) {
var addr = (el.getAttribute("data-blockie") || "").toLowerCase();
var rng = mulberry32(seedFrom(addr || "0x"));
function hue() { return Math.floor(rng() * 360); }
var h1 = hue();
var h2 = (h1 + 80 + Math.floor(rng() * 160)) % 360;
var h3 = (h2 + 60 + Math.floor(rng() * 120)) % 360;
var ang = Math.floor(rng() * 360);
var px = Math.floor(rng() * 100);
var py = Math.floor(rng() * 100);
el.style.backgroundImage =
"radial-gradient(circle at " + px + "% " + py + "%, hsl(" + h3 + " 90% 62%), transparent 60%)," +
"linear-gradient(" + ang + "deg, hsl(" + h1 + " 85% 58%), hsl(" + h2 + " 80% 50%))";
}
document.querySelectorAll("[data-blockie]").forEach(paintBlockie);
/* ---------- address helpers ---------- */
function truncate(addr) {
if (!addr || addr.length < 12) return addr || "";
return addr.slice(0, 6) + "…" + addr.slice(-4);
}
// Pre-fill title attributes with the full address for accessibility.
document.querySelectorAll(".chip[data-address]").forEach(function (chip) {
var full = chip.getAttribute("data-address");
chip.setAttribute("title", full);
});
/* ---------- toast ---------- */
var wrap = document.getElementById("toastWrap");
function toast(msg, hash) {
var el = document.createElement("div");
el.className = "toast";
el.setAttribute("role", "status");
var dot = document.createElement("span");
dot.className = "t-dot";
el.appendChild(dot);
var label = document.createElement("span");
label.textContent = msg;
el.appendChild(label);
if (hash) {
var h = document.createElement("span");
h.className = "t-hash";
h.textContent = hash;
el.appendChild(h);
}
wrap.appendChild(el);
var ttl = setTimeout(dismiss, 2600);
function dismiss() {
clearTimeout(ttl);
el.classList.add("out");
el.addEventListener("animationend", function () { el.remove(); }, { once: true });
}
}
/* ---------- copy to clipboard ---------- */
function copyText(text) {
if (navigator.clipboard && navigator.clipboard.writeText) {
return navigator.clipboard.writeText(text);
}
return new Promise(function (resolve, reject) {
try {
var ta = document.createElement("textarea");
ta.value = text;
ta.setAttribute("readonly", "");
ta.style.position = "absolute";
ta.style.left = "-9999px";
document.body.appendChild(ta);
ta.select();
document.execCommand("copy");
document.body.removeChild(ta);
resolve();
} catch (e) { reject(e); }
});
}
document.querySelectorAll("[data-copy]").forEach(function (chip) {
var locked = false;
chip.addEventListener("click", function () {
var addr = chip.getAttribute("data-address");
copyText(addr).then(function () {
if (!locked) {
locked = true;
chip.classList.add("copied");
setTimeout(function () {
chip.classList.remove("copied");
locked = false;
}, 1400);
}
toast("Address copied", truncate(addr));
}).catch(function () {
toast("Couldn't access clipboard");
});
});
});
/* ---------- explorer links (simulated) ---------- */
document.querySelectorAll("[data-explorer]").forEach(function (link) {
var addr = link.getAttribute("data-explorer");
// Fictional explorer — kept as a hash so nothing navigates off-page.
link.setAttribute("href", "#lumenscan/address/" + addr);
link.addEventListener("click", function (e) {
e.preventDefault();
toast("Opening on Lumen Scan", truncate(addr));
});
});
/* ---------- hero: toggle raw / ENS ---------- */
var toggle = document.getElementById("toggleEns");
if (toggle) {
var heroChip = document.querySelector(".hero .chip-copy");
var heroName = document.getElementById("heroName");
var addrEl = heroChip ? heroChip.querySelector("[data-addr]") : null;
var fullAddr = heroChip ? heroChip.getAttribute("data-address") : "";
var ensName = "nova.lumen";
var showingEns = true;
function render() {
if (showingEns) {
if (heroName) heroName.textContent = ensName;
if (addrEl) addrEl.textContent = truncate(fullAddr);
toggle.querySelector(".ti").textContent = "Showing ENS";
toggle.setAttribute("aria-pressed", "true");
} else {
if (heroName) heroName.textContent = truncate(fullAddr);
if (addrEl) addrEl.textContent = truncate(fullAddr);
toggle.querySelector(".ti").textContent = "Showing raw";
toggle.setAttribute("aria-pressed", "false");
}
}
toggle.addEventListener("click", function () {
showingEns = !showingEns;
render();
toast(showingEns ? "Resolved to nova.lumen" : "Showing raw address");
});
render();
}
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Web3 — Address Chip</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<main class="page">
<header class="masthead">
<div class="brand">
<span class="brand-mark" aria-hidden="true"></span>
<div>
<h1>Address Chip</h1>
<p class="sub">truncate · copy · ENS — a reusable wallet identity primitive</p>
</div>
</div>
<div class="net-pill" role="status" aria-label="Connected network">
<span class="dot" aria-hidden="true"></span>
Lumen Chain
</div>
</header>
<!-- Hero account card -->
<section class="hero" aria-label="Primary account">
<div class="hero-inner">
<div class="hero-id">
<span class="blockie hero-blockie" data-blockie="0x7a3f9c2e8b41d05a6f7c0e9a1b2c3d4e5f60c41d" aria-hidden="true"></span>
<div class="hero-meta">
<div class="hero-name-row">
<span class="hero-name" id="heroName">nova.lumen</span>
<span class="verified" title="Primary name verified" aria-label="Verified name">✓</span>
</div>
<button class="chip chip-copy chip-lg" data-address="0x7a3f9c2e8b41d05a6f7c0e9a1b2c3d4e5f60c41d" data-copy aria-label="Copy address 0x7a3f…c41d">
<span class="blockie chip-blockie" data-blockie="0x7a3f9c2e8b41d05a6f7c0e9a1b2c3d4e5f60c41d" aria-hidden="true"></span>
<span class="addr mono" data-addr>0x7a3f…c41d</span>
<span class="status-dot" data-status="online" title="Online"></span>
<span class="copy-ic" aria-hidden="true">
<svg class="ic-copy" viewBox="0 0 24 24" width="15" height="15"><path d="M9 9h9v9H9zM6 6h9v3M6 6v9h3" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linejoin="round"/></svg>
<svg class="ic-check" viewBox="0 0 24 24" width="15" height="15"><path d="M5 12.5l4.2 4.2L19 7" fill="none" stroke="currentColor" stroke-width="2.1" stroke-linecap="round" stroke-linejoin="round"/></svg>
</span>
</button>
</div>
</div>
<div class="hero-actions">
<button class="ghost-btn" id="toggleEns" aria-pressed="true">
<span class="ti">Showing ENS</span>
</button>
<a class="ghost-btn" data-explorer="0x7a3f9c2e8b41d05a6f7c0e9a1b2c3d4e5f60c41d" href="#" target="_blank" rel="noopener">
Explorer
<svg viewBox="0 0 24 24" width="13" height="13" aria-hidden="true"><path d="M7 17L17 7M9 7h8v8" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"/></svg>
</a>
</div>
</div>
</section>
<!-- Variant gallery -->
<section class="block" aria-labelledby="varTitle">
<h2 id="varTitle" class="block-title">Variants</h2>
<p class="block-note">Every chip below is the same component in a different mode. Click any copy chip to copy its address.</p>
<div class="grid">
<article class="card">
<header class="card-h"><h3>Raw · truncated</h3><span class="tag">default</span></header>
<div class="card-body">
<span class="chip" data-address="0x4b81c0a7f3e29d6b8a1f04c7e2d903b6f1a8c20e">
<span class="addr mono" data-addr>0x4b81…c20e</span>
</span>
<p class="card-cap">Monospace, middle-truncated. Title attribute carries the full hash.</p>
</div>
</article>
<article class="card">
<header class="card-h"><h3>ENS resolved</h3><span class="tag tag-accent">name</span></header>
<div class="card-body">
<span class="chip chip-ens" data-address="0x2f1a9b6c0d3e7458a90f12c3b4d5e6f701a2b3c4">
<span class="blockie chip-blockie" data-blockie="0x2f1a9b6c0d3e7458a90f12c3b4d5e6f701a2b3c4" aria-hidden="true"></span>
<span class="addr mono">orbital.lumen</span>
</span>
<p class="card-cap">Resolved name with a gradient blockie avatar derived from the address bytes.</p>
</div>
</article>
<article class="card">
<header class="card-h"><h3>Copy on click</h3><span class="tag tag-accent">action</span></header>
<div class="card-body">
<button class="chip chip-copy" data-address="0x9c0e1f2a3b4c5d6e7f8091a2b3c4d5e6f7081920" data-copy aria-label="Copy address">
<span class="addr mono" data-addr>0x9c0e…1920</span>
<span class="copy-ic" aria-hidden="true">
<svg class="ic-copy" viewBox="0 0 24 24" width="14" height="14"><path d="M9 9h9v9H9zM6 6h9v3M6 6v9h3" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linejoin="round"/></svg>
<svg class="ic-check" viewBox="0 0 24 24" width="14" height="14"><path d="M5 12.5l4.2 4.2L19 7" fill="none" stroke="currentColor" stroke-width="2.1" stroke-linecap="round" stroke-linejoin="round"/></svg>
</span>
</button>
<p class="card-cap">Clipboard write + toast + a checkmark flip that settles back after a beat.</p>
</div>
</article>
<article class="card">
<header class="card-h"><h3>Explorer link</h3><span class="tag">link</span></header>
<div class="card-body">
<a class="chip chip-link" data-explorer="0x55ed7c1a9b0f3e2d4c6a8b0d2f4e6081a3c5d7e9" data-address="0x55ed7c1a9b0f3e2d4c6a8b0d2f4e6081a3c5d7e9" href="#" target="_blank" rel="noopener">
<span class="blockie chip-blockie" data-blockie="0x55ed7c1a9b0f3e2d4c6a8b0d2f4e6081a3c5d7e9" aria-hidden="true"></span>
<span class="addr mono" data-addr>0x55ed…d7e9</span>
<svg class="link-ic" viewBox="0 0 24 24" width="13" height="13" aria-hidden="true"><path d="M7 17L17 7M9 7h8v8" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"/></svg>
</a>
<p class="card-cap">Opens the address on Lumen Scan (simulated — intercepted with a toast).</p>
</div>
</article>
</div>
</section>
<!-- Sizes + status -->
<section class="block" aria-labelledby="sizeTitle">
<h2 id="sizeTitle" class="block-title">Sizes & status</h2>
<p class="block-note">One chip, three densities. Status dots flag liveness at a glance.</p>
<div class="size-row">
<div class="size-cell">
<span class="size-label">small</span>
<button class="chip chip-sm chip-copy" data-address="0x1029384756abcdef1029384756abcdef10293847" data-copy aria-label="Copy small address">
<span class="blockie chip-blockie" data-blockie="0x1029384756abcdef1029384756abcdef10293847" aria-hidden="true"></span>
<span class="addr mono" data-addr>0x1029…3847</span>
<span class="status-dot" data-status="online" title="Online"></span>
</button>
</div>
<div class="size-cell">
<span class="size-label">medium</span>
<button class="chip chip-md chip-copy" data-address="0xaa12bb34cc56dd78ee90ff01234567890abcdeff" data-copy aria-label="Copy medium address">
<span class="blockie chip-blockie" data-blockie="0xaa12bb34cc56dd78ee90ff01234567890abcdeff" aria-hidden="true"></span>
<span class="addr mono" data-addr>0xaa12…deff</span>
<span class="status-dot" data-status="idle" title="Idle"></span>
</button>
</div>
<div class="size-cell">
<span class="size-label">large</span>
<button class="chip chip-lg chip-copy" data-address="0xf00dcafe1234567890abcdef0fedcba987654321" data-copy aria-label="Copy large address">
<span class="blockie chip-blockie" data-blockie="0xf00dcafe1234567890abcdef0fedcba987654321" aria-hidden="true"></span>
<span class="addr mono" data-addr>0xf00d…4321</span>
<span class="status-dot" data-status="offline" title="Offline"></span>
</button>
</div>
</div>
<div class="legend" aria-hidden="true">
<span><i class="lg online"></i>online</span>
<span><i class="lg idle"></i>idle</span>
<span><i class="lg offline"></i>offline</span>
</div>
</section>
<footer class="foot">
<p class="mono">demo · no real wallet, RPC, or on-chain calls</p>
</footer>
</main>
<div class="toast-wrap" id="toastWrap" aria-live="polite" aria-atomic="true"></div>
<script src="script.js"></script>
</body>
</html>Address Chip (truncate · copy · ENS)
The single most repeated primitive in any wallet, explorer, or DeFi dashboard is the address chip — and this is that chip in every form it usually takes. A hero account card pairs a 56px gradient blockie with a resolved name and a large copy chip, then a variant gallery breaks the component down into its modes: a raw middle-truncated address (0x4b81…c20e) in JetBrains Mono, an ENS-resolved name with its own avatar, a copy-on-click action, and an explorer link. Each blockie is generated deterministically from the address string, so the same wallet always renders the same little gradient.
Interactions are all client-side and self-contained. Clicking any copy chip writes the full address to the clipboard, fires a toast that echoes the truncated hash, and flips its icon from copy to a green checkmark before settling back. The hero card’s toggle switches between the ENS name and the raw address, and the explorer chips intercept their click to show a simulated Opening on Lumen Scan toast instead of navigating away. Everything is keyboard-usable with visible focus rings.
A sizes-and-status row shows the chip at small, medium, and large densities, each carrying an online, idle, or offline status dot with a small legend below. The layout is glassy and neon-accented, collapses to a single column at 360px, and respects prefers-reduced-motion. No frameworks, no web3 libraries — just HTML, CSS, and vanilla JS.
UI-only simulation — no real wallet, RPC, or on-chain calls. Mock data, fictional tokens.