textarea, File Uploads and Hidden Fields

Three controls with their own rules: a textarea whose value is its content, a file input that needs the right enctype, and hidden fields that are not secret.

textarea

A multi line text box. Unlike input, it is not a void element, and its value is the text between the tags rather than a value attribute.

<label for="message">Your message</label>
<textarea id="message" name="message" rows="6" cols="40"></textarea>

This creates a real trap. Whitespace inside the tags is content, so writing it on separate lines gives the field a leading newline:

<!-- starts with a blank line -->
<textarea name="bio">
</textarea>

<!-- empty, as intended -->
<textarea name="bio"></textarea>

<!-- with a starting value -->
<textarea name="bio">Tell us about yourself</textarea>
AttributeEffect
rowsVisible lines of text
colsVisible width in characters
maxlength / minlengthCharacter limits
wrapsoft (default) or hard, which inserts real line breaks on submit
placeholder, required, readonlyAs on input

Prefer CSS to cols for width, since a percentage width is responsive and a character count is not:

textarea {
  width: 100%;
  min-height: 8rem;
  resize: vertical;     /* let readers grow it, but not sideways */
  font: inherit;        /* browsers default to a monospace font */
}

A visible character counter helps when there is a limit. Put it in a live region so it is announced without stealing focus:

<textarea id="bio" name="bio" maxlength="300" aria-describedby="bio-count"></textarea>
<p id="bio-count" aria-live="polite">300 characters remaining</p>

File uploads

<form action="/upload" method="post" enctype="multipart/form-data">
  <label for="photo">Passport photograph</label>
  <input type="file" id="photo" name="photo"
         accept="image/jpeg,image/png" required>

  <button type="submit">Upload</button>
</form>

Two things are mandatory and both are easy to forget:

  • method="post". A file cannot travel in a URL.
  • enctype="multipart/form-data". Without it the browser sends only the file name, and the upload silently fails with no error anywhere.

accept

<input type="file" accept="image/*">                      <!-- any image -->
<input type="file" accept=".pdf,.doc,.docx">              <!-- by extension -->
<input type="file" accept="image/jpeg,image/png">         <!-- by media type -->
<input type="file" accept="image/*" capture="environment"> <!-- open the camera -->

accept filters the file chooser. It is a convenience, not a security control - the reader can select any file, and the file type must be verified on the server by inspecting the contents rather than trusting the extension or the declared type.

Multiple files

<input type="file" name="documents[]" multiple accept=".pdf">

Styling

The file input cannot be styled. The usual approach is to hide it correctly - not with display: none - and style the label as a button:

<label for="photo" class="file-button">Choose a photograph</label>
<input type="file" id="photo" name="photo" class="visually-hidden">
<span id="file-name" aria-live="polite">No file chosen</span>

The label already focuses and activates the input, so no script is needed to open the chooser. A script is needed only to display the chosen file name.

Server side limits

Nothing in HTML limits file size. That is enforced by the server, and on PHP it is governed by upload_max_filesize, post_max_size and max_file_uploads. A file exceeding the limit is rejected before your code runs, so handle that case explicitly rather than assuming an upload always arrives.

Hidden fields

<input type="hidden" name="form_id" value="enquiry-2026">
<input type="hidden" name="redirect_to" value="/thank-you">
<input type="hidden" name="csrf_token" value="a1b2c3d4e5f6">

A hidden field is submitted like any other but is never displayed. It carries state the server needs and the reader does not set.

Hidden does not mean secret. The value is in the page source, visible in view source, in the Elements panel and in the Network tab, and it can be edited before submission with two clicks. Never put a price, a user id, a role, a discount amount or anything else security relevant in one and trust it on the way back.

<!-- dangerous: the reader can edit this to 1 -->
<input type="hidden" name="price" value="4999">

<!-- safe: an identifier the server resolves to a price it owns -->
<input type="hidden" name="product_id" value="kettle-2l">

The one legitimate security use is a CSRF token: a value the server generated, sent to this reader, and verifies on the way back. Its safety comes from the server knowing what it issued, not from the field being hidden.

Important rules

  • A textarea value is its content; whitespace inside the tags is part of the value.
  • File uploads need post and multipart/form-data.
  • accept is a filter, not a validator.
  • A hidden field is fully visible and fully editable by the reader.
  • Hidden fields need no label, since there is nothing to interact with.
  • A disabled hidden field is not submitted.

Common mistakes

  • Writing a textarea across two lines and shipping a leading newline in every value.
  • Forgetting enctype and getting an upload that silently does nothing.
  • Trusting accept as a security measure.
  • Putting a price or a user id in a hidden field and using it on the server.
  • Hiding a file input with display: none, removing it from the tab order.
  • Using cols for width instead of CSS.
  • Assuming a file always arrives, and crashing when the server limit rejects it.

Best practices

  • Write <textarea></textarea> on one line when it should start empty.
  • Set textarea width in CSS and allow vertical resizing only.
  • Show a live character counter when there is a limit.
  • Always set accept to narrow the chooser, and always validate on the server.
  • State the accepted formats and the maximum size in visible text next to the field.
  • Send identifiers in hidden fields, never values the server can look up itself.
  • Include a CSRF token in every state changing form.

Practice

  1. Write a textarea over two lines, submit it, and inspect the value the server receives.
  2. Build an upload form without enctype and observe what arrives, then add it.
  3. Open DevTools, change a hidden field value and submit. Explain what a server must do to be safe.
  4. Build a styled file chooser using a label, and confirm it is reachable by keyboard.

Useful resources

Hand picked references for this topic
Written by Lorens Mishra

Default administrator account created by the installer.

Continue reading

All HTML notes →

Discussion

0 comments
Sign in to join the discussion.

No comments yet. Be the first to say something.