- Gist written up and documented by Rich (RichLewis.com)
- Free to use under the MIT License
A one-click bookmarklet that shows a floating tooltip with the font in use (stack + likely active face), size, weight, line-height, letter/word spacing, and color for whatever text you hover over on a web page.
- Esc to quit
- Hold ⌥ Option / Alt to freeze the panel on the current element; release to resume
- Displays:
- Element tag, ID, and class
- Font stack (
font-family
) - Likely active font (via
document.fonts.check()
) - Size, weight, style, line-height, letter/word spacing
- Text and background colors
- Copy the Minified bookmarklet code shown later in this file.
- Create a new bookmark in your browser.
- Paste the code into the URL/location field.
- Name it e.g. Font Peek.
- Visit any page and click on the bookmark. Hover over text to see details.
Click on the bookmarklet (in your browser bookmarks pane or bookmarks toolbar) then click on any text on a web page. A floating box will appear showing the name of the font being used for that text.
Esc to quit.
Hold ⌥ Option / Alt to freeze the panel on the current element; release to resume.
-
Browser extensions:
- WhatFont (Chrome) – hover over text, see font instantly
- Fontanello (Firefox/Chrome) – right-click text to see font details
-
Online tools:
- Fonts Ninja – browser extension with preview/download options
- WhatTheFont – identify fonts from images/screenshots
The 'stack' of fonts displayed shows the intent of the web page author to show a certain font style; the browser uses the first installed face that supports the glyphs. The bookmarklet flags a likely active family with document.fonts.check(...). It’s accurate for most Latin text; mixed scripts or missing glyphs can still fall back per character.
Some sites use Content Security Policy that blocks inline scripts (bookmarklets). If this bookmarklet doesn’t work:
- Paste the code into the browser's DevTools console (CSP doesn’t block that).
- Install a browser extension like WhatFont (Chrome) or Fontanello (FireFox). Extensions get around CSP because they’re “trusted” by the browser.
- Save as a userscript in Tampermonkey/Greasemonkey, which also runs in a trusted context.
Paste this as the bookmark URL following to the instructions above:
javascript:(()=>{if(window.__fontPeekCleanup){window.__fontPeekCleanup();return}const d=document,w=window;const box=d.createElement('div');Object.assign(box.style,{position:'fixed',zIndex:2147483647,top:'10px',right:'10px',maxWidth:'420px',fontFamily:'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace',fontSize:'12px',lineHeight:'1.4',background:'rgba(20,20,24,.92)',color:'#eef',padding:'10px 12px',borderRadius:'10px',boxShadow:'0 6px 24px rgba(0,0,0,.35)',whiteSpace:'pre-wrap',pointerEvents:'none'});box.innerHTML='Font Peek… hover any text (Esc to exit)';d.body.appendChild(box);let frozen=false;const q=(s)=>s.replace(/["']/g,'').trim();const likelyFont=(fam)=>{try{if(!('fonts'in d))return null;const list=fam.split(',').map(q);for(const name of list){if(name&&d.fonts.check('16px '+(/[\s]/.test(name)?`"${name}"`:name)))return name}return null}catch(e){return null}};const fmtColor=(c)=>{try{const ctx=d.createElement('canvas').getContext('2d');ctx.fillStyle=c;return ctx.fillStyle}catch{ return c}};const brief=(text,max=140)=>text.length>max?text.slice(0,max-1)+'…':text;const onMove=(ev)=>{if(frozen)return;const el=ev.target;if(!(el&&el.nodeType===1))return;const cs=w.getComputedStyle(el);if(!cs)return;const fam=cs.fontFamily||'';const active=likelyFont(fam);const color=fmtColor(cs.color);const bg=fmtColor(cs.backgroundColor);const lh=cs.lineHeight;const ls=cs.letterSpacing;const ws=cs.wordSpacing;const fw=cs.fontWeight;const fs=cs.fontStyle;const sz=cs.fontSize;const tt=cs.textTransform;const ff=brief(fam,260);box.innerHTML=`Element: <${el.tagName.toLowerCase()}${el.id?`#${el.id}`:''}${el.className?'.'+Array.from(el.classList).join('.') : ''}>\nfont-family: ${ff}\nlikely active: ${active??'(unknown)'}\nfont-size: ${sz} | weight: ${fw} | style: ${fs}\nline-height: ${lh} | letter-spacing: ${ls} | word-spacing: ${ws}\ncolor: ${color} | bg: ${bg}\ntext-transform: ${tt}`};const onKey=(e)=>{if(e.key==='Escape'){cleanup()} if(e.key==='Alt'){}};const onDown=(e)=>{if(e.key==='Alt')frozen=true};const onUp=(e)=>{if(e.key==='Alt')frozen=false};const cleanup=()=>{w.removeEventListener('mousemove',onMove,true);w.removeEventListener('keydown',onKey,true);w.removeEventListener('keyup',onUp,true);w.removeEventListener('keydown',onDown,true);box.remove();delete w.__fontPeekCleanup};w.addEventListener('mousemove',onMove,true);w.addEventListener('keydown',onKey,true);w.addEventListener('keyup',onUp,true);w.addEventListener('keydown',onDown,true);w.__fontPeekCleanup=cleanup;})();
📝 Readable version of the source code If you want to audit or tweak it, you can use this formatted source. You don’t need this for the bookmark -— use the minified one above. This code has the same logic, it is just expanded for clarity.
(() => {
if (window.__fontPeekCleanup) { window.__fontPeekCleanup(); return; }
const d = document, w = window;
// Floating info box
const box = d.createElement('div');
Object.assign(box.style, {
position: 'fixed',
zIndex: 2147483647,
top: '10px',
right: '10px',
maxWidth: '420px',
fontFamily:
'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace',
fontSize: '12px',
lineHeight: '1.4',
background: 'rgba(20,20,24,.92)',
color: '#eef',
padding: '10px 12px',
borderRadius: '10px',
boxShadow: '0 6px 24px rgba(0,0,0,.35)',
whiteSpace: 'pre-wrap',
pointerEvents: 'none'
});
box.innerHTML = 'Font Peek… hover any text (Esc to exit)';
d.body.appendChild(box);
let frozen = false;
const stripQuotes = (s) => s.replace(/["']/g, '').trim();
// Try to guess the actual active face using the FontFaceSet API
const likelyFont = (family) => {
try {
if (!('fonts' in d)) return null;
const list = family.split(',').map(stripQuotes);
for (const name of list) {
if (!name) continue;
const probe = /[\s]/.test(name) ? `"${name}"` : name;
if (d.fonts.check(`16px ${probe}`)) return name;
}
return null;
} catch {
return null;
}
};
const cssColor = (c) => {
try {
const ctx = d.createElement('canvas').getContext('2d');
ctx.fillStyle = c;
return ctx.fillStyle;
} catch {
return c;
}
};
const brief = (text, max = 260) =>
text.length > max ? text.slice(0, max - 1) + '…' : text;
const onMove = (ev) => {
if (frozen) return;
const el = ev.target;
if (!(el && el.nodeType === 1)) return;
const cs = w.getComputedStyle(el);
if (!cs) return;
const fam = cs.fontFamily || '';
const active = likelyFont(fam);
const color = cssColor(cs.color);
const bg = cssColor(cs.backgroundColor);
const info = [
`Element: <${el.tagName.toLowerCase()}${el.id ? `#${el.id}` : ''}${el.className ? '.' + Array.from(el.classList).join('.') : ''}>`,
`font-family: ${brief(fam)}`,
`likely active: ${active ?? '(unknown)'}`,
`font-size: ${cs.fontSize} | weight: ${cs.fontWeight} | style: ${cs.fontStyle}`,
`line-height: ${cs.lineHeight} | letter-spacing: ${cs.letterSpacing} | word-spacing: ${cs.wordSpacing}`,
`color: ${color} | bg: ${bg}`,
`text-transform: ${cs.textTransform}`
].join('\n');
box.innerHTML = info;
};
const onKey = (e) => {
if (e.key === 'Escape') cleanup();
};
const onDown = (e) => {
if (e.key === 'Alt') frozen = true;
};
const onUp = (e) => {
if (e.key === 'Alt') frozen = false;
};
const cleanup = () => {
w.removeEventListener('mousemove', onMove, true);
w.removeEventListener('keydown', onKey, true);
w.removeEventListener('keyup', onUp, true);
w.removeEventListener('keydown', onDown, true);
box.remove();
delete w.__fontPeekCleanup;
};
w.addEventListener('mousemove', onMove, true);
w.addEventListener('keydown', onKey, true);
w.addEventListener('keyup', onUp, true);
w.addEventListener('keydown', onDown, true);
w.__fontPeekCleanup = cleanup;
})();
MIT License
Copyright (c) 2025 Rich Lewis
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.