Question
HTML Entity Encoding in Input Values with JavaScript and jQuery
Question
An HTML hidden input contains an encoded ampersand:
<input id="hiddenId" type="hidden" value="chalk & cheese">
When JavaScript or jQuery reads its value, the result is chalk & cheese rather than the literal text chalk & cheese:
$('#hiddenId').attr('value');
Why is the HTML entity decoded when the attribute is read? How can a string be HTML-encoded in JavaScript or jQuery so that the literal entity text can be displayed in a text input?
Short Answer
You will learn that HTML entities such as & are syntax in an HTML document, not automatically preserved text. You will also learn when to use .val(), why browser parsing decodes entities, and how to encode a string safely when you truly need an HTML-encoded representation.
Concept
HTML is parsed before your JavaScript runs. During parsing, the browser recognizes character references (often called HTML entities).
<input value="chalk & cheese">
The source code contains the five characters &, but the browser interprets them as one ampersand character, &. Therefore, the DOM value represented by that markup is:
chalk & cheese
This is expected behavior. & is how an ampersand is written safely in HTML source; it is not the data value the input stores after parsing.
There are two different goals that are easy to confuse:
- Store/display an ampersand as data: use
chalk & cheesein JavaScript and assign it through DOM APIs. - Create HTML source text safely: encode the ampersand as
chalk & cheesebefore inserting it into an HTML string or serializing HTML. - Display the literal characters
&in a text box: the input's value must actually contain those five characters, so encode&into&and assign that result with.val()or.value.
The distinction matters for correctness and security. Encoding is context-dependent: text placed into HTML, an HTML attribute, a URL, and JavaScript source each have different escaping rules.
Mental Model
Think of HTML entities as notation on a shipping label.
- In the HTML file,
&is an instruction meaning “put an ampersand here.” - Once the browser has read the label, the stored item is simply
&. - Reading the input with JavaScript reads the stored item, not the original ink used on the label.
If you want a text box to visibly show &, you must store the characters &, a, m, p, and ; as its value. The browser will not recreate them automatically because it cannot know whether the original source used &, &, or a literal &.
Syntax and Examples
Use the DOM value API when reading or changing form controls.
<input id="hiddenId" type="hidden" value="chalk & cheese">
<input id="displayId" type="text">
const rawValue = $('#hiddenId').val();
console.log(rawValue); // "chalk & cheese"
$('#displayId').val(rawValue);
The visible text input shows:
chalk & cheese
That is usually the correct result: the entity has already been decoded into the real character.
If you specifically need the literal entity text, encode the value first:
function encodeHtmlAttribute(value) {
return String(value)
.replace(/&/g, '&')
.replace(/"/g, '"')
.replace(/'/g, ''')
.replace(/</g, '<')
.replace(/>/g, '>');
}
const rawValue = $('#hiddenId').val();
const encodedValue = encodeHtmlAttribute(rawValue);
$('#displayId').val(encodedValue);
Now the text box displays:
chalk & cheese
Using .val() is preferred for form controls. attr('value') refers to the HTML attribute, which represents the initial/default value, while .val() reads or sets the control's current value.
Step by Step Execution
Consider this example:
<input id="hiddenId" type="hidden" value="chalk & cheese">
<input id="outputId" type="text">
const valueFromHiddenInput = $('#hiddenId').val();
const entityText = valueFromHiddenInput.replace(/&/g, '&');
$('#outputId').val(entityText);
Execution trace:
- The browser parses
value="chalk & cheese". - While parsing, it converts
&into the single character&. $('#hiddenId').val()returns"chalk & cheese"..replace(/&/g, '&')creates the new JavaScript string"chalk & cheese"..val(entityText)assigns that string directly as the text input's value.- A text input does not parse its value as HTML, so it visibly shows
chalk & cheese.
If you instead put entityText into an HTML string, the browser would parse it again. That is why direct DOM APIs are clearer and safer for updating existing elements.
Real World Use Cases
- Editing HTML snippets: A CMS may show encoded markup such as
Tom & Jerryin a source-editor field. - Generating HTML on the server: Dynamic text must be escaped before it is placed inside an HTML attribute or text node.
- Displaying raw markup in documentation: Code examples often need literal
<,>, and&characters represented safely. - Form values: Values should normally remain normal data, such as
Research & Development; encode only when producing HTML text. - API and database data: Store the original text when possible. Encode at the output boundary where the text is rendered into HTML.
Real Codebase Usage
In real projects, avoid building HTML with string concatenation when you can use DOM APIs.
const name = 'Research & Development';
const input = document.querySelector('#companyName');
input.value = name;
No HTML encoding is needed because input.value treats name as data, not markup.
For regular page text, use textContent:
const message = '<strong>Saved</strong> & verified';
document.querySelector('#status').textContent = message;
This displays the angle brackets and ampersand as text rather than interpreting them as HTML.
When an application must generate an HTML string, escape for the specific context first:
const label = 'A "quoted" value & more';
const safeLabel = encodeHtmlAttribute(label);
const html = `<input type="text" value="${safeLabel}">`;
Common codebase pattern: keep data unencoded internally, then encode only at the boundary where it enters HTML. This reduces double-encoding bugs such as &amp;.
Common Mistakes
Expecting source entities to remain in the DOM
<input value="chalk & cheese">
After parsing, the DOM value is chalk & cheese. HTML entities are decoded by design.
Avoid it: Treat the decoded value as the real data. Encode only if you need an HTML representation.
Using .attr('value') for the current form value
$('#name').attr('value');
This can describe the initial attribute value rather than the value currently edited by the user.
Avoid it: Use .val() for jQuery form-control values.
$('#name').val();
Encoding only ampersands for general HTML output
const unsafe = value.replace(/&/g, '&');
This is enough only when the sole requirement is to show a literal ampersand in a text input. It does not safely handle quotes or angle brackets when creating HTML.
Avoid it: Escape the characters required by the destination context, or use textContent, .value, and framework templating APIs instead of HTML strings.
Double encoding
const once = 'chalk & cheese'.replace(/&/g, '&');
const twice = once.replace(/&/g, '&');
console.log(twice); // "chalk &amp; cheese"
Avoid it: Keep raw values as data and perform encoding once at the output boundary.
Using .html() with untrusted text
$('#message').html(userInput);
This can interpret user input as markup and may create an XSS vulnerability.
Avoid it: Use .text(userInput) for visible text, or .val(userInput) for an input value.
Comparisons
| Task | Recommended API | Does the browser parse the string as HTML? |
|---|---|---|
| Read a form control's current value | $('#id').val() / element.value | No |
| Set a form control's displayed value | $('#id').val(value) / element.value = value | No |
| Display plain text in an element | $('#id').text(value) / element.textContent = value | No |
| Insert markup intentionally | $('#id').html(markup) / element.innerHTML = markup | Yes |
| Read the default HTML attribute value | $('#id').attr('value') | The original attribute was already parsed |
& versus &:
| Representation | Meaning |
|---|---|
& in HTML source | A safe HTML character reference for & |
& in a JavaScript string | The actual ampersand character |
& in a JavaScript string assigned with .val() | Five literal characters shown in the input |
& inserted through innerHTML | Parsed and displayed as & |
Cheat Sheet
- HTML parsing converts
&into&. - Use
.val()to get or set a form control's current value. - Use
.attr('value')only when you specifically need the element's value attribute/default value. - Use
.val('chalk & cheese')to show literal&in a text input. - Use
textContentor jQuery.text()to display untrusted text in ordinary elements. - Avoid
.html()/innerHTMLfor untrusted values. - Keep application data raw, such as
chalk & cheese. - Encode once, only when creating HTML source or another representation that requires it.
const encodeAmpersands = value => String(value).replace(/&/g, '&');
$('#output').val(encodeAmpersands($('#hiddenId').val()));
FAQ
Why does JavaScript change & into &?
JavaScript is reading the parsed DOM value. The browser decoded & while it parsed the HTML document.
Should I use .attr('value') or .val() in jQuery?
Use .val() for the current value of an <input>, <textarea>, or <select>. Use .attr('value') only when you specifically need the HTML attribute/default value.
How do I make an input display & literally?
Assign a JavaScript string containing those literal characters with .val():
$('#output').val('chalk & cheese');
Does an input value need HTML encoding?
Not when you set it with .val() or .value. Those APIs assign data directly. Encoding is needed when you construct HTML source text.
Can I recover the exact original entity spelling from the DOM?
Usually no. After parsing, &, &, and possibly a literal & represent the same DOM character. Preserve the original source separately if that distinction matters.
Is escape() the right JavaScript function for HTML encoding?
No. escape() is obsolete and was not designed for HTML escaping. encodeURIComponent() is for URL components, not HTML.
Does HTML encoding prevent all security problems?
No. Escaping must match the output context. Prefer APIs such as textContent and .value, which avoid HTML parsing for plain text.
Mini Project
Description
Build a small value preview tool. It reads a hidden input containing an ampersand, shows the normal decoded value, and can show an HTML-attribute-encoded representation. This demonstrates the difference between data in the DOM and text used to represent that data in HTML.
Goal
Read an input value correctly and display both its raw value and its HTML-encoded representation without using innerHTML for dynamic text.
Requirements
Create a hidden input whose source value contains &.
Read the hidden input using its current value.
Show the decoded value in one text input.
Show an HTML-encoded representation in another text input.
Use DOM value APIs rather than inserting dynamic strings with innerHTML.
Keep learning
Related questions
Add a Favicon to a Static HTML Page
Learn how to add a favicon to static HTML pages, use correct paths and icon formats, and troubleshoot browser caching and local-file issues.
Allow Only Numeric Input (0-9) in HTML Input Using jQuery
Learn how to allow only digits 0-9 in an HTML input using jQuery, with examples, validation tips, common mistakes, and best practices.
Apply CSS !important with jQuery .css()
Learn why jQuery .css() cannot set !important and how to use CSSStyleDeclaration.setProperty() to apply inline important styles safely.