Source Code

<div class="dl-phone">
  <div class="dl-screen">
    <div class="dl-display">
      <div class="dl-num" id="dlNum">&nbsp;</div>
      <div class="dl-name" id="dlName"></div>
    </div>
    <div class="dl-pad" id="dlPad">
      <button data-k="1"><b>1</b><small>&nbsp;</small></button>
      <button data-k="2"><b>2</b><small>ABC</small></button>
      <button data-k="3"><b>3</b><small>DEF</small></button>
      <button data-k="4"><b>4</b><small>GHI</small></button>
      <button data-k="5"><b>5</b><small>JKL</small></button>
      <button data-k="6"><b>6</b><small>MNO</small></button>
      <button data-k="7"><b>7</b><small>PQRS</small></button>
      <button data-k="8"><b>8</b><small>TUV</small></button>
      <button data-k="9"><b>9</b><small>WXYZ</small></button>
      <button data-k="*"><b>&lowast;</b><small>&nbsp;</small></button>
      <button data-k="0"><b>0</b><small>+</small></button>
      <button data-k="#"><b>#</b><small>&nbsp;</small></button>
    </div>
    <div class="dl-actions">
      <span class="dl-spacer"></span>
      <button class="dl-call" id="dlCall" aria-label="Call">
        <svg viewBox="0 0 24 24" width="26" fill="#fff"><path d="M6.6 10.8a15.5 15.5 0 0 0 6.6 6.6l2.2-2.2a1 1 0 0 1 1-.24 11 11 0 0 0 3.5.56 1 1 0 0 1 1 1V20a1 1 0 0 1-1 1A17 17 0 0 1 3 4a1 1 0 0 1 1-1h3.5a1 1 0 0 1 1 1c0 1.2.2 2.4.56 3.5a1 1 0 0 1-.25 1z"/></svg>
      </button>
      <button class="dl-del" id="dlDel" aria-label="Delete">
        <svg viewBox="0 0 24 24" width="24" fill="none" stroke="#94a3b8" stroke-width="2" stroke-linecap="round"><path d="M21 5H9L3 12l6 7h12z"/><path d="M14 9l-4 6M10 9l4 6"/></svg>
      </button>
    </div>
  </div>
</div>

Dialer Keypad — Free Phone Dialpad UI HTML CSS Snippet

Dialer Keypad · Mobile · Plain HTML, CSS & JS · Live preview

What's included

Features

Classic 3×4 pad
Digits with letter groups and 0 carrying +.
Live formatting
Groups digits into a readable phone number.
Symbol-safe
Formatting skips * and # codes.
Caller-ID lookup
Matches a contacts map to show a name.
Smart delete key
Appears when needed; double-tap clears.
Calling animation
The call button pulses on dial.
Tactile keys
Buttons depress and scale on press.
No dependency
Pure HTML/CSS/JS for dialers and softphones.

About this UI Snippet

Dialer Keypad — Phone Dialpad with Number Formatting

Screenshot of the Dialer Keypad snippet rendered live

A dialer keypad is the phone app's number pad — a 3×4 grid of digits with letters beneath them, a growing number display, a green call button, and a delete key. This snippet builds a faithful, interactive one inside a CSS phone frame, with live number formatting, caller-ID lookup, and a calling animation, in HTML, CSS, and vanilla JavaScript with no dependency.

The classic 3×4 pad

The keypad is a CSS grid of circular buttons, each showing a large digit and the small letter group beneath it (ABC, DEF, …) exactly like a real phone, with 0 carrying a + for international dialing. Buttons are aspect-ratio: 1 circles that depress on :active (background and a slight scale) for tactile feedback. Taps are handled by one delegated listener on the pad that appends the pressed key, capped at 15 digits.

Live phone-number formatting

As you dial, format() groups the digits into a readable US-style number — (123) 456 7890 — using a single replace with a capture-group callback that wraps the area code in parentheses and spaces the rest, but only once enough digits are present and the input is purely numeric (so */# codes aren't mangled). The display updates on every keypress.

Caller-ID lookup

A small CONTACTS map simulates a phonebook: when the dialed string matches a known number, a green name line appears beneath the display — the caller-ID match you see when dialing a saved contact. It's a stand-in for a real contacts query, showing exactly where you'd plug one in.

Delete and call behavior

The delete key only appears once there's something to erase (it fades in via a .show class), removes the last digit on tap, and clears everything on double-tap (the press-and-hold equivalent). The call button pulses with a dlPulse keyframe and shows "Calling…" for a moment — the placeholder for initiating a real call.

Reusing it

Swap CONTACTS for your real address book, change format() to your locale's grouping, and wire the call button to a tel: link or your VoIP/WebRTC SDK. It works as the dialer in a softphone, a contact app, or any phone mockup demo.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Rather than tracing the regex yourself, paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly what the capture groups in format()'s replace call are matching and why the function bails out for strings containing star or pound characters. The same assistant is useful for optimizing it too, for instance checking whether calling render() on every single keypress is wasteful for a 15-digit cap or whether that's already cheap enough to ignore. It is also a fast way to extend the dialer: ask it to wire the CONTACTS lookup to a real fetch-based address book, support international number formats beyond the US-style grouping, or add a long-press-to-clear gesture on touch devices instead of relying on double-tap. Treat the code less like a finished artifact and more like a starting point for a conversation.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a phone dialer keypad UI in plain HTML, CSS, and JavaScript with no library, inside a CSS-only phone frame.

Requirements:
- A 3x4 grid of circular buttons for 0-9, star, and pound, each button showing a large digit plus small letter groupings underneath it exactly like a real phone (ABC under 2, DEF under 3, and so on, with a plus sign under 0), built with a single delegated click listener on the grid container rather than one listener per button.
- A running dialed-digits string capped at a maximum length, appended to on each keypress and re-rendered into a display line above the pad.
- A live formatting function that groups digits into a readable phone number (e.g. area code in parentheses, then two more groups) only once enough digits are present and only when the string is purely numeric, so star/pound dial codes are left unformatted.
- A small in-memory contacts lookup object mapping known digit strings to names, checked on every render so a caller-ID-style name appears beneath the number display when the dialed digits match a known contact.
- A delete key that is visually hidden (not just disabled) until there is at least one digit dialed, removes the last digit on a single tap, and clears the entire number on a double-tap as a stand-in for a press-and-hold gesture.
- A call button that, on click, plays a pulsing CSS animation and shows a temporary "Calling..." status text for about two seconds before resetting, with the button disabled while the fake call is in progress.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSA dialer keypad renders inside a phone frame.
  2. 2
    Tap the digitsThe number builds in the display above the pad.
  3. 3
    Watch the formattingOnce long enough it groups into (123) 456 7890.
  4. 4
    Dial a known numberA matching contact name appears in green.
  5. 5
    Delete or callThe delete key erases; double-tap clears; call pulses.
  6. 6
    Wire it upConnect CONTACTS and the call button to your stack.

Real-world uses

Common Use Cases

Phone and dialer apps
A dialpad inside a phone mockup.
Softphones and VoIP
Wire the call button to a WebRTC stack.
OTP and PIN entry
A fuller alternative to a PIN pad.
Contact apps
Pair caller-ID with a country selector for codes.
Kiosk dialers
Reuse the grid beside a phone input field.
Learning input formatting
A reference for live phone-number grouping.
Related: Control Center Panel
See the Control Center Panel for a related mobile pattern worth pairing with this one.
Related: Keyboard-Safe Fixed Input Bar with the VisualViewport API
See the Keyboard-Safe Fixed Input Bar with the VisualViewport API for a related mobile pattern worth pairing with this one.
Related: Mobile OTP Verification Screen
See the Mobile OTP Verification Screen for a related mobile pattern worth pairing with this one.
Related: Mobile Permission Request Screen
See the Mobile Permission Request Screen for a related mobile pattern worth pairing with this one.
Related: Mobile Split Bill Screen
See the Mobile Split Bill Screen for a related mobile pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

As digits are entered, a format() function groups them into a US-style number like (123) 456 7890 using a single regex replace with a capture-group callback that wraps the area code in parentheses and spaces the rest. It only formats once there are enough digits and the input is all numbers, so star and pound codes aren't altered.

A small CONTACTS object maps numbers to names. On each keypress, the dialed string is looked up in that map, and if it matches, the contact's name is shown in green beneath the number — the caller-ID match for a saved contact. In a real app you'd replace the map with a query against your address book.

It only shows when there's something to delete. A show class fades it in once the dialed string is non-empty, mirroring real dialers where the backspace appears after you start typing. Tapping it removes the last digit, and double-tapping clears the whole number, standing in for press-and-hold to clear.

Wire its click handler to a tel: link (window.location.href = 'tel:' + digits) for the device dialer, or to your VoIP/WebRTC SDK to place an in-app call. The snippet shows a calling animation as a placeholder; replace the timeout with your call-initiation logic and update the status line from call events.

Hold the dialed digits in state, append on key press, and derive the formatted display and caller-ID name from it. The delete key visibility binds to whether the string is non-empty. Keep format() and the contacts lookup as pure helpers. In Tailwind, build the pad with a grid and aspect-square circular buttons.