HTML forms
The HTML textarea, explained.
A <textarea> is the multi-line text box every contact form needs for the message itself. Here is how to size it, limit it, style it and let it grow, and the few ways it behaves differently from an <input>.
Updated 7 November 2026
The basic textarea
<label for="message">Message</label>
<textarea id="message" name="message" rows="5" required></textarea>- It needs a closing tag. Unlike
<input>, a textarea is written as an opening and a closing tag, even when it starts empty. - rows sets the visible height in lines, and cols the width in characters. Most sites set the width with CSS instead of
cols. - name is the key the text is sent under. A textarea without a name is not sent at all.
- required stops the form from being sent while the box is empty.
- A visible label, linked with
forandid, tells screen-reader users what to type.
Default text goes between the tags
A textarea has no value attribute. Text you want in the box when the page loads goes between the opening and closing tags, and it is sent like anything the visitor types.
<label for="notes">Notes</label>
<textarea id="notes" name="notes" rows="4">Anything we should know before the call?</textarea>If you only want a hint that disappears when someone types, use placeholder instead. A placeholder is never sent, and it is not a replacement for a label. In JavaScript, read and set the current text with textarea.value.
Limit the length
maxlength stops typing and pasting at that many characters. minlength asks for at least that many before the form will send, though an empty optional field is still allowed.
<label for="bio">Short bio</label>
<textarea id="bio" name="bio" rows="4" minlength="20" maxlength="500"
placeholder="A few sentences about you"></textarea>Like every browser check, these only help honest visitors: whatever receives the form has to cope with any length. Heartdove accepts up to 10,000 characters per field.
Style a textarea
Two defaults catch people out: textareas use a monospace font in most browsers, and visitors can drag the corner to resize them. These rules fix both and make the box fill its container.
textarea {
width: 100%;
box-sizing: border-box;
font: inherit; /* textareas use a monospace font by default in most browsers */
line-height: 1.5;
padding: 10px 12px;
resize: vertical; /* or none, horizontal, both */
}Make it grow with the text
The CSS property field-sizing: content lets a textarea grow as the visitor types. It works in Chrome and Edge and is still arriving in other browsers; a browser without it ignores the rule and keeps the height from rows, which is a safe fallback. Pair it with a maximum height so a long message scrolls instead of pushing the page down.
/* Grows with its content in browsers that support it; others keep the rows height */
textarea { field-sizing: content; min-height: 5lh; max-height: 20lh; }For the same effect everywhere, resize it with a few lines of JavaScript:
const box = document.querySelector('#message');
function fit() {
box.style.height = 'auto';
box.style.height = box.scrollHeight + 'px';
}
box.addEventListener('input', fit);
fit();Show a character counter
With a maxlength, a live count tells visitors how much room is left. aria-describedby connects the count to the field, and aria-live lets screen readers announce it.
<label for="message">Message</label>
<textarea id="message" name="message" rows="5" maxlength="500"
aria-describedby="message-count"></textarea>
<p id="message-count" aria-live="polite">0 of 500 characters</p>
<script>
const box = document.querySelector('#message');
const count = document.querySelector('#message-count');
box.addEventListener('input', () => {
count.textContent = `${box.value.length} of ${box.maxLength} characters`;
});
</script>A form that sends
On its own a textarea goes nowhere: the form needs an action that receives it. This form posts to Heartdove, which saves every message, emails you an alert and tracks it until it is delivered or bounces. A field named message appears as the message body in your inbox and in the alert.
<form action="https://submit.heartdove.com/v1/submit" method="POST">
<input type="hidden" name="access_key" value="YOUR_ACCESS_KEY" />
<label for="email">Email</label>
<input id="email" type="email" name="email" autocomplete="email" required />
<label for="message">Message</label>
<textarea id="message" name="message" rows="6" maxlength="5000" required></textarea>
<input type="checkbox" name="botcheck" tabindex="-1" autocomplete="off" style="display:none" />
<button type="submit">Send message</button>
</form>Replace YOUR_ACCESS_KEY with your key from a free Heartdove form. The hidden botcheck field is a spam trap that people never see. To add dropdowns, radio buttons or checkboxes, use the contact form generator.
Questions
Why does value="..." not work on a textarea?
A textarea has no value attribute. Put the starting text between the opening and closing tags, or set it with textarea.value in JavaScript.
How do I stop a textarea from being resized?
Add resize: none in CSS. resize: vertical keeps it resizable in height only, which is usually the friendlier choice.
How do I keep line breaks when I show the text later?
The submitted text contains the line breaks the visitor typed. When you display it in HTML, use white-space: pre-wrap on the element, or convert the line breaks to <br> tags after escaping the text.
What is the difference between rows and height?
rows sets the starting height in lines of text, so it follows the font size. A CSS height or min-height overrides it.
Never lose another enquiry.
Connect your first form in a few minutes. Your existing design stays exactly as it is.