Hidden Form Fields

The Concept

Hidden form fields embed state directly in HTML forms as invisible <input> elements. When the form is submitted, this hidden data travels with the visible form data.

<form action="/checkout" method="POST">
    <input type="hidden" name="cart_id" value="abc123">
    <input type="hidden" name="step" value="2">

    <!-- Visible fields -->
    <input type="text" name="address">
    <button type="submit">Continue</button>
</form>

How It Works

Step 1: Browser renders form with hidden field (from previous step) ┌────────────────────────────────────────────┐ │ <form action="step2.php" method="POST"> │ │ <input type="hidden" name="name" │ │ value="Alice"> ← invisible │ │ <input type="email" name="email"> │ │ <button>Next</button> │ │ </form> │ └────────────────────────────────────────────┘ │ │ User fills email, clicks Submit │ POST: name=Alice&email=alice@example.com ▼ Step 2: Server receives ALL form data (hidden + visible) ┌────────────────────────────────────────────┐ │ $_POST['name'] → "Alice" (hidden) │ │ $_POST['email'] → "alice@example.com" │ └────────────────────────────────────────────┘ │ │ Server builds NEXT page, embedding │ accumulated data as hidden fields ▼ Step 3: Server generates new HTML with data embedded ┌────────────────────────────────────────────┐ │ <form action="step3.php" method="POST"> │ │ <input type="hidden" name="name" │ │ value="Alice"> ← carried │ │ <input type="hidden" name="email" │ │ value="alice@..."> ← carried │ │ <input type="text" name="phone"> │ │ <button>Submit</button> │ │ </form> │ └────────────────────────────────────────────┘ │ │ Cycle repeats: user submits, │ server receives all data, │ generates next page... ▼

The key insight: the server must actively embed the data into each response. The hidden fields don't persist on their own - PHP (or any server language) reads the incoming data and writes it back into the next form.

Multi-Step Form Demo

The classic use case for hidden fields is a multi-step wizard. Each step carries forward data from previous steps.

Start Multi-Step Demo
Try it: Go through the 3-step form. At each step, right-click and "View Page Source" to see the hidden fields carrying your previous answers forward.

Comparison: Hidden Fields vs Other Methods

Aspect Hidden Fields URL Parameters Sessions
Visibility In page source In address bar Server only
Persistence Form submission only Bookmarkable Configurable
Size Limit Unlimited ~2KB Unlimited
Security User can modify Visible to all Most secure
Back Button May lose data Works perfectly Works

Critical Security Warning

Hidden fields are NOT secure!

Despite being invisible in the browser, users can:

<?php
// DANGER: Trusting hidden field for authorization
$price = $_POST['price'];  // User changed this from 99.99 to 0.01!
chargeCustomer($price);    // VULNERABLE

// SAFE: Server looks up the real price
$productId = $_POST['product_id'];
$price = getProductPrice($productId);  // From database
chargeCustomer($price);
?>

When to Use Hidden Fields

Good use cases: Avoid for:

The PHP Code

<?php
// step1.php - Collect name
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $name = $_POST['name'] ?? '';
    ?>
    <form action="step2.php" method="POST">
        <!-- Carry name forward as hidden field -->
        <input type="hidden" name="name"
               value="<?= htmlspecialchars($name, ENT_QUOTES, 'UTF-8') ?>">

        <label>Email: <input type="email" name="email" required></label>
        <button type="submit">Next</button>
    </form>
    <?php
}
?>

Historical Note: ASP.NET ViewState

Microsoft's ASP.NET Web Forms (2002-2010s) made extensive use of hidden fields through a mechanism called ViewState. This automated the pattern we're doing manually above.

How ViewState worked:

ASP.NET automatically serialized the entire page state (control values, properties, etc.) into a single hidden field:

<input type="hidden" name="__VIEWSTATE"
       value="dDwtMTI4NzYzND...very long base64 string..." />

On each "postback" (form submission back to the same page), the framework would:

  1. Deserialize the ViewState
  2. Restore all control values
  3. Run event handlers
  4. Re-serialize the updated state
  5. Send back the new page with updated ViewState

This created the illusion of stateful, desktop-like programming on the stateless web. A button click felt like a Windows Forms event.

ViewState problems:

Modern frameworks (ASP.NET MVC, Core) abandoned this pattern in favor of explicit state management similar to what other frameworks use.

Understanding ViewState helps explain why hidden fields are powerful but should be used judiciously. The lesson: don't try to hide the stateless nature of HTTP - work with it.


Back to State Management | Sessions Demo | Security Patterns