📌 Solo numeri o solo lettere nei campi input

Scopri come permettere solo numeri o solo lettere nei campi input con una soluzione semplice e concreta in PHP, CSS e JavaScript, con spiegazione chiara e demo pronta da usare.

Schermo con due campi di inserimento affiancati, circondati da numeri sul lato sinistro e lettere sul destro.

Autore: alessiopuppi · Creato: 06/03/2026 19:48

Come permettere solo numeri o solo lettere nei campi input con PHP, CSS e JavaScript

Nel web esistono problemi piccoli solo in apparenza. Limitare un campo input a soli numeri o a sole lettere sembra una di quelle operazioni banali che si risolvono in pochi secondi con una riga di codice e un po’ di leggerezza. In realtà è proprio qui che molti esempi online iniziano a cedere. Funzionano in superficie, ma appena l’utente incolla del testo, usa una tastiera diversa o invia dati alterati, il comportamento si incrina.

Il punto è semplice: un form non deve solo sembrare corretto. Deve esserlo davvero. Per questo conviene affrontare il problema con un criterio tecnico pulito, separando i ruoli dei vari livelli. HTML organizza il modulo, JavaScript filtra il contenuto in tempo reale e PHP esegue il controllo finale lato server. Quando questi tre elementi lavorano insieme, il risultato non è una demo ornamentale, ma una soluzione concreta e riutilizzabile.

Quando serve un controllo di questo tipo

Ci sono molti casi in cui limitare i caratteri ammessi in un input è perfettamente sensato. Un campo che contiene un codice, un identificativo o un numero interno può richiedere esclusivamente cifre. Un campo nome, invece, può richiedere solo lettere, spazi e qualche segno grafico legittimo come apostrofi o trattini. In tutti questi casi il problema non è solo estetico: si tratta di impedire che nel sistema entrino dati incoerenti già al primo passaggio.

Lasciare un campo troppo permissivo significa spesso demandare il caos alle fasi successive. E quando il caos arriva nel backend, nei database o nelle validazioni più avanti nel flusso, il costo logico aumenta. Conviene quindi agire prima, con ordine.

Perché HTML da solo non basta

HTML offre strumenti utili come inputmode, pattern e required. Sono attributi importanti, ma non vanno trattati come una fortezza. inputmode, per esempio, può suggerire una tastiera numerica su smartphone, ma non obbliga il valore del campo a essere numerico. pattern aiuta nella validazione del modulo, ma non filtra da solo il contenuto mentre l’utente scrive. Sono indizi, non sentenze.

Questo significa che HTML, da solo, non basta per ottenere un comportamento davvero solido. È il primo strato. Non la soluzione completa.

Perché serve JavaScript

JavaScript migliora l’esperienza utente in modo immediato. Invece di lasciare che l’utente scriva qualsiasi cosa per poi scoprire l’errore solo al momento dell’invio, lo script ripulisce il contenuto in tempo reale. Se il campo deve accettare solo numeri, elimina lettere e simboli. Se deve accettare solo lettere, rimuove cifre e caratteri non previsti.

Questo approccio non è una misura di sicurezza definitiva, ma è un miglioramento netto dell’usabilità. Il form diventa più leggibile, più coerente e meno fastidioso. L’utente capisce subito il comportamento corretto del campo senza dover combattere con messaggi tardivi o correzioni inutili.

Perché PHP resta decisivo

La verifica finale spetta sempre al server. Questa è la regola fondamentale che separa lo sviluppo serio dai tutorial fatti di cartone. Anche se il browser si comporta bene, PHP deve controllare nuovamente i dati ricevuti. Se il campo numerico contiene caratteri non ammessi, va rifiutato. Se il campo alfabetico contiene simboli o cifre fuori specifica, va rifiutato allo stesso modo.

Il browser aiuta. Lo script filtra. Ma è il server che decide. Questo non è un dettaglio tecnico secondario: è il principio che impedisce al sistema di fidarsi ingenuamente dell’interfaccia.

La logica dell’esempio

L’esempio seguente è organizzato in tre file distinti. index.php contiene il modulo e la validazione lato server. style.css definisce l’aspetto grafico della demo. script.js filtra i caratteri durante la digitazione. La struttura è semplice, leggibile e facilmente adattabile a progetti reali.

Nel caso specifico, il primo campo accetta solo numeri. Il secondo accetta lettere, spazi, apostrofi e trattini. Questa seconda scelta è più realistica rispetto a un banale “solo lettere ASCII”, perché i nomi reali non vivono in un laboratorio sterilizzato.

File index.php

<?php
declare(strict_types=1);

$numberValue = '';
$letterValue = '';
$numberError = '';
$letterError = '';
$successMessage = '';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $numberValue = isset($_POST['only_numbers']) ? trim((string) $_POST['only_numbers']) : '';
    $letterValue = isset($_POST['only_letters']) ? trim((string) $_POST['only_letters']) : '';

    if ($numberValue === '' || !preg_match('/^\d+$/', $numberValue)) {
        $numberError = 'Inserisci solo numeri nel primo campo.';
    }

    if ($letterValue === '' || !preg_match("/^[\p{L}\s'’-]+$/u", $letterValue)) {
        $letterError = 'Inserisci solo lettere nel secondo campo.';
    }

    if ($numberError === '' && $letterError === '') {
        $successMessage = 'Dati validi inviati correttamente.';
    }
}
?>
<!DOCTYPE html>
<html lang="it">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Come permettere solo numeri o solo lettere nei campi input con PHP, CSS e JavaScript</title>
  <meta name="description" content="Scopri come permettere solo numeri o solo lettere nei campi input con PHP, CSS e JavaScript, con spiegazione chiara e codice completo in tre file.">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="wrapper">
    <div class="demo-box">
      <h1>Solo numeri o solo lettere negli input</h1>
      <p class="intro">
        In questa demo il primo campo accetta solo numeri, mentre il secondo accetta
        solo lettere, spazi, apostrofi e trattini.
      </p>

      <form action="" method="post" novalidate>
        <div class="field">
          <label for="only_numbers">Campo con soli numeri</label>
          <input
            id="only_numbers"
            name="only_numbers"
            type="text"
            inputmode="numeric"
            autocomplete="off"
            spellcheck="false"
            data-filter="digits"
            placeholder="Esempio: 123456"
            value="<?php echo htmlspecialchars($numberValue, ENT_QUOTES, 'UTF-8'); ?>"
          >
          <?php if ($numberError !== ''): ?>
            <p class="message error"><?php echo htmlspecialchars($numberError, ENT_QUOTES, 'UTF-8'); ?></p>
          <?php endif; ?>
        </div>

        <div class="field">
          <label for="only_letters">Campo con sole lettere</label>
          <input
            id="only_letters"
            name="only_letters"
            type="text"
            autocomplete="name"
            spellcheck="false"
            data-filter="letters"
            placeholder="Esempio: Alessio Puppi"
            value="<?php echo htmlspecialchars($letterValue, ENT_QUOTES, 'UTF-8'); ?>"
          >
          <?php if ($letterError !== ''): ?>
            <p class="message error"><?php echo htmlspecialchars($letterError, ENT_QUOTES, 'UTF-8'); ?></p>
          <?php endif; ?>
        </div>

        <button type="submit">Invia</button>

        <?php if ($successMessage !== ''): ?>
          <p class="message success"><?php echo htmlspecialchars($successMessage, ENT_QUOTES, 'UTF-8'); ?></p>
        <?php endif; ?>
      </form>
    </div>
  </main>

  <script src="script.js"></script>
</body>
</html>

File style.css

:root {
  --bg-1: #0f172a;
  --bg-2: #020617;
  --panel: rgba(15, 23, 42, 0.9);
  --line: #334155;
  --text: #e5e7eb;
  --muted: #94a3b8;
  --accent: #38bdf8;
  --accent-2: #0ea5e9;
  --danger: #f87171;
  --success: #4ade80;
  --shadow: 0 22px 60px rgba(0, 0, 0, 0.35);
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  font-family: Arial, Helvetica, sans-serif;
  background: linear-gradient(180deg, var(--bg-1), var(--bg-2));
  color: var(--text);
  line-height: 1.6;
}

.wrapper {
  width: min(900px, calc(100% - 32px));
  margin: 48px auto;
}

.demo-box {
  padding: 32px;
  border: 1px solid var(--line);
  border-radius: 24px;
  background: var(--panel);
  box-shadow: var(--shadow);
}

h1 {
  margin: 0 0 14px;
  font-size: clamp(2rem, 4vw, 2.8rem);
  line-height: 1.15;
}

.intro {
  margin: 0 0 24px;
  color: var(--muted);
}

.field + .field {
  margin-top: 18px;
}

label {
  display: block;
  margin-bottom: 8px;
  font-weight: 700;
}

input {
  width: 100%;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: #111827;
  color: var(--text);
  font: inherit;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

input::placeholder {
  color: #64748b;
}

input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 4px rgba(56, 189, 248, 0.15);
}

button {
  margin-top: 20px;
  padding: 13px 18px;
  border: 0;
  border-radius: 14px;
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  color: #082f49;
  font: inherit;
  font-weight: 800;
  cursor: pointer;
  transition: transform 0.2s ease, filter 0.2s ease;
}

button:hover {
  transform: translateY(-1px);
  filter: brightness(1.05);
}

.message {
  margin-top: 10px;
  padding: 10px 12px;
  border-radius: 10px;
  font-size: 0.95rem;
}

.error {
  border: 1px solid rgba(248, 113, 113, 0.35);
  background: rgba(127, 29, 29, 0.22);
  color: #fecaca;
}

.success {
  border: 1px solid rgba(74, 222, 128, 0.35);
  background: rgba(20, 83, 45, 0.22);
  color: #bbf7d0;
}

@media (max-width: 700px) {
  .demo-box {
    padding: 22px;
    border-radius: 18px;
  }

  h1 {
    font-size: 2rem;
  }
}

File script.js

(() => {
  const digitsDisallowed = /\D+/g;
  const lettersDisallowed = /[^A-Za-zÀ-ÖØ-öø-ÿ\s'’-]+/g;

  function sanitize(value, mode) {
    if (mode === "digits") {
      return value.replace(digitsDisallowed, "");
    }

    if (mode === "letters") {
      return value
        .replace(lettersDisallowed, "")
        .replace(/\s{2,}/g, " ");
    }

    return value;
  }

  function sanitizeAndPreserveCaret(input, mode) {
    const rawValue = input.value;
    const start = input.selectionStart ?? rawValue.length;
    const end = input.selectionEnd ?? rawValue.length;
    const cleanValue = sanitize(rawValue, mode);

    if (rawValue === cleanValue) {
      return;
    }

    const cleanBeforeStart = sanitize(rawValue.slice(0, start), mode);
    const cleanBeforeEnd = sanitize(rawValue.slice(0, end), mode);

    input.value = cleanValue;
    input.setSelectionRange(cleanBeforeStart.length, cleanBeforeEnd.length);
  }

  function bindFilter(input) {
    const mode = input.dataset.filter;

    input.addEventListener("input", () => {
      sanitizeAndPreserveCaret(input, mode);
    });

    input.addEventListener("blur", () => {
      if (mode === "letters") {
        input.value = input.value.trim().replace(/\s{2,}/g, " ");
      }
    });
  }

  document.querySelectorAll("input[data-filter]").forEach(bindFilter);
})();

Perché questa soluzione è più solida delle scorciatoie comuni

Molti snippet online fanno una sola cosa: bloccano qualche carattere mentre si scrive. È il minimo sindacale, e spesso nemmeno quello. Qui invece la struttura è più corretta perché ogni livello svolge il proprio compito senza invadere quello degli altri. HTML costruisce il modulo, CSS lo rende leggibile, JavaScript filtra in tempo reale e PHP verifica davvero il dato.

Questa separazione dei ruoli rende il codice più chiaro, più riutilizzabile e più facile da adattare a casi reali. Ed evita il vizio peggiore dei tutorial frettolosi: far sembrare “risolto” ciò che in realtà è stato soltanto nascosto sotto il tappeto.

Conclusione

Permettere solo numeri o solo lettere nei campi input è una necessità comune, ma non va trattata con soluzioni improvvisate. Il principio corretto è netto: il browser guida, lo script filtra, il server convalida. Quando questi tre livelli sono allineati, il form non solo appare ordinato, ma si comporta anche in modo coerente e affidabile.

Nel web, le piccole imprecisioni diventano grandi se lasciate proliferare. Per questo anche un controllo apparentemente semplice merita una struttura pulita. Non per mania di perfezione, ma per rispetto della logica del sistema.

Dopo la parte teorica e il codice completo, qui sotto puoi provare direttamente una demo funzionante integrata nella pagina.

Demo pratica

Il primo campo accetta solo numeri. Il secondo solo lettere, spazi, apostrofi e trattini.

Messaggio sponsorizzato
Pubblicità

🔗 Condividi l'articolo:

Autore: alessiopuppi · Creato: 06/03/2026 19:48 · Ultima modifica: 03/09/2026 12:17