Text
WORD FREQUENCY
Paste any text to see how often each word appears. Filter common stopwords, sort by frequency or alphabetically, and export as CSV.
Sort: freq ↓
A–Z
Show top words
Paste text above to analyze word frequency.
Developer Reference
Core Algorithm & Standalone Script
Standalone, zero-dependency JavaScript implementation powering this tool. Free to inspect, copy, and build upon.
const STOPWORDS = new Set(['a','an','the','and','or','but','in','on','at','to','for','of','with','by','from','is','was','are','were','be','been','being','have','has','had','do','does','did','will','would','could','should','may','might','shall','can','need','dare','ought','used','it','its','this','that','these','those','i','me','my','myself','we','our','ours','ourselves','you','your','yours','yourself','yourselves','he','him','his','himself','she','her','hers','herself','they','them','their','theirs','themselves','what','which','who','whom','when','where','why','how','all','both','each','few','more','most','other','some','such','no','not','only','same','so','than','too','very','just','because','as','until','while','if','then','else','any','about','above','after','before','between','during','into','through','up','down','out','off','over','under','again','once','s','t','re','ve','m','ll','d']);
let freqData = [];
let filterStop = true;
let caseSensitive = false;
let sortMode = 'freq';
function analyze() {
const text = document.getElementById('textInput').value;
if (!text.trim()) {
freqData = [];
document.getElementById('statsRow').style.display = 'none';
document.getElementById('tableWrap').innerHTML = '<div class="empty-state">Paste text above to analyze word frequency.</div>';
return;
}
const words = text.match(/[a-zA-Z''\u00C0-\u024F]+/g) || [];
const sentences = (text.match(/[.!?]+/g) || []).length || 1;
const totalWords = words.length;
const processed = caseSensitive ? words : words.map(w => w.toLowerCase());
const filtered = filterStop ? processed.filter(w => !STOPWORDS.has(w.toLowerCase())) : processed;
const map = {};
filtered.forEach(w => { map[w] = (map[w] || 0) + 1; });
freqData = Object.entries(map);
const uniqueAll = Object.keys(map).length;
const avgLen = filtered.length ? (filtered.reduce((s,w)=>s+w.length,0)/filtered.length).toFixed(1) : 0;
document.getElementById('sTotal').textContent = totalWords.toLocaleString();
document.getElementById('sUnique').textContent = uniqueAll.toLocaleString();
document.getElementById('sSentences').textContent = sentences.toLocaleString();
document.getElementById('sAvgLen').textContent = avgLen;
document.getElementById('statsRow').style.display = 'grid';
renderTable();
}
function renderTable() {
if (!freqData.length) return;
const topN = Math.max(1, parseInt(document.getElementById('topN').value) || 50);
let sorted = [...freqData];
if (sortMode === 'freq') sorted.sort((a,b) => b[1]-a[1] || a[0].localeCompare(b[0]));
else sorted.sort((a,b) => a[0].localeCompare(b[0]));
const slice = sorted.slice(0, topN);
const maxCount = slice[0] ? (sortMode === 'freq' ? slice[0][1] : Math.max(...slice.map(x=>x[1]))) : 1;
const total = freqData.reduce((s,[,c])=>s+c,0);
let html = `<table class="freq-table"><thead><tr><th>Rank</th><th>Word</th><th>Count</th><th>%</th><th class="bar-cell">Frequency</th></tr></thead><tbody>`;
const allSorted = [...freqData].sort((a,b)=>b[1]-a[1]);
slice.forEach(([word, count]) => {
const rank = allSorted.findIndex(([w])=>w===word) + 1;
const pct = ((count/total)*100).toFixed(1);
const barW = Math.round((count/maxCount)*100);
html += `<tr><td class="rank">#${rank}</td><td>${esc(word)}</td><td>${count.toLocaleString()}</td><td class="pct">${pct}%</td><td class="bar-cell"><div class="bar-track"><div class="bar-fill" style="width:${barW}%"></div></div></td></tr>`;
});
html += '</tbody></table>';
document.getElementById('tableWrap').innerHTML = html;
}
function esc(s) { return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); }
function toggleStopwords() {
filterStop = !filterStop;
document.getElementById('btnStopwords').classList.toggle('active', filterStop);
analyze();
}
function toggleCase() {
caseSensitive = !caseSensitive;
document.getElementById('btnCase').classList.toggle('active', caseSensitive);
analyze();
}
function setSort(mode) {
sortMode = mode;
document.getElementById('sortFreq').classList.toggle('active', mode === 'freq');
document.getElementById('sortAlpha').classList.toggle('active', mode === 'alpha');
renderTable();
}
function exportCSV() {
if (!freqData.length) return;
const sorted = [...freqData].sort((a,b)=>b[1]-a[1]);
const total = sorted.reduce((s,[,c])=>s+c,0);
let csv = 'Rank,Word,Count,Percentage\n';
sorted.forEach(([word, count], i) => {
csv += `${i+1},"${word.replace(/"/g,'""')}",${count},${((count/total)*100).toFixed(2)}%\n`;
});
const a = document.createElement('a');
a.href = URL.createObjectURL(new Blob([csv], { type: 'text/csv' }));
a.download = 'word-frequency.csv';
a.click();
URL.revokeObjectURL(a.href);
}