You've built a page. It sits there, quiet. Today we'll teach it to do things — count, remember, react — with a language called JavaScript. And we'll do it in ten lines, with an example anyone from any tradition understands: a counter you can press, that remembers. The demo above is a tasbih — thirty-three, sixty-six, ninety-nine. Same pattern, same shape as anything else you'd build.
If HTML is the nouns of a web page and CSS is the adjectives, JavaScript is the verbs. Press, open, close, save, show, hide, count — these are all verbs. Learn four commands, and you can make most small apps yourself.
The one tag you need
Add this anywhere inside your <body>, usually near the bottom:
<script>
console.log('The pen has been taught. Now the hand.')
</script>
Save, refresh, open the browser's DevTools with F12 (or Cmd+Option+I on macOS), and click the Console tab. You'll see the message. You just ran code — no compiler, no server; the browser read your words and executed them.
Example 1: a tasbih counter — ten lines, real interactivity
<button id="bead" type="button">SubhanAllah</button>
<div id="count">0</div>
<script>
let n = 0
const bead = document.querySelector('#bead')
const countEl = document.querySelector('#count')
bead.addEventListener('click', () => {
n += 1
countEl.textContent = n
})
</script>
Eight lines of JavaScript. A complete, working interactive app. Let's read them together:
let n = 0— a memory cell that starts at zero.document.querySelector('#bead')— find the button whoseidisbead. Same selector grammar as CSS.addEventListener('click', …)— "when the user clicks, run this function."n += 1— increment.countEl.textContent = n— replace the displayed number.
That's the whole vocabulary of interactive web pages: find an element, listen for an event, change something. You now know the recipe every framework is built on top of.
Example 2: mark every thirty-third press
The demo at the top of this post adds one small extension: every thirty-third click gets a visual pulse, and a ring of text says which tier of the tasbih we're in. Same shape, just a conditional:
if (n % 33 === 0) {
countEl.classList.add('pulse')
ringEl.textContent =
n === 33 ? 'SubhanAllah × 33'
: n === 66 ? 'Alhamdulillah × 33'
: n === 99 ? 'Allahu Akbar × 33'
: ''
setTimeout(() => countEl.classList.remove('pulse'), 500)
}
Three ideas worth carrying:
-
The modulo operator
%returns the remainder.n % 33 === 0is true exactly at 33, 66, 99 — a cheap way to mark regular milestones in any counter. -
classList.add/removeis JavaScript's best role. Flip a class; let CSS handle the visuals. The.pulseclass in the demo is justcolor: #5d00ff; transition: color 0.25s;— no animation logic in the JS. -
setTimeout(fn, ms)runs something later. It's the most common async function on the web. No need to learn async theory before you use it.
Example 3: remember across page reloads
The browser ships with a tiny key-value database called localStorage.
It is the easiest backend you will ever meet — no server, no database
file, no password. Persist your tasbih count so it survives a tab close:
let n = Number(localStorage.getItem('tasbih') || 0)
countEl.textContent = n
bead.addEventListener('click', () => {
n += 1
countEl.textContent = n
localStorage.setItem('tasbih', n)
})
Click, close the tab, reopen — your count is still there. Ten lines of JavaScript just built an auto-saving counter with no backend at all.
Tricks worth carrying
-
querySelectorunderstands any CSS selector.document.querySelector('.card:nth-child(2) button')works. You already know the selector language from CSS. -
Prefer
textContentoverinnerHTML.innerHTMLrenders HTML — fine for trusted content, risky for user input.textContentalways treats the value as plain text. Safety first, cleverness second. -
addEventListeneris the only event API you need. Forgetonclick="…"strings in HTML. One function, one place, cleaner code. -
localStorageholds about 5 MB per site. Counters, todo lists, settings — none of them need a backend. -
Arrow functions (
() => {}) are shorter function declarations. They're everywhere in modern code — not magical, just concise.
What frameworks add — and what they don't replace
React, Vue, Svelte — these speed up two specific things: rendering
lists that change a lot and reusing UI across many pages.
If your project has neither problem, you don't need a framework. A ten-line
<script> tag is perfectly serious engineering.
And the language itself — document.querySelector,
addEventListener, arrow functions, localStorage —
stays exactly the same underneath every framework. Learn this once, carry
it forever.
Takeaways
- JavaScript runs inside any HTML file with a
<script>tag — no setup needed. - Four things cover most interactivity: find, listen, change, remember.
- The browser is your IDE. DevTools let you read, tweak, and debug live.
- Small apps deserve small code. Ten lines is enough for real value.
Next post: "How a URL actually works — the 0.3 second journey" — the six small protocols holding hands behind every page load.
Build small, build honest, and keep your code light.