Question

HTML Entity Encoding in Input Values with JavaScript and jQuery

htmljavascriptjqueryescapinghtml-escape-characters

Question

An HTML hidden input contains an encoded ampersand:

<input id="hiddenId" type="hidden" value="chalk &amp; cheese">

When JavaScript or jQuery reads its value, the result is chalk & cheese rather than the literal text chalk &amp; 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 &amp; 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 &amp; cheese">

The source code contains the five characters &amp;, but the browser interprets them as one ampersand character, &. Therefore, the DOM value represented by that markup is:

chalk & cheese

This is expected behavior. &amp; 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 & cheese in JavaScript and assign it through DOM APIs.
  • Create HTML source text safely: encode the ampersand as chalk &amp; cheese before inserting it into an HTML string or serializing HTML.
  • Display the literal characters &amp; in a text box: the input's value must actually contain those five characters, so encode & into &amp; 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, &amp; 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 &amp;, 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 &amp;, &#38;, or a literal &.

Take Quiz

Syntax and Examples

Use the DOM value API when reading or changing form controls.

<input id="hiddenId" type="hidden" value="chalk &amp; 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, '&amp;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&#39;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;');
}

const rawValue = $('#hiddenId').val();
const encodedValue = encodeHtmlAttribute(rawValue);

$('#displayId').val(encodedValue);

Now the text box displays:

chalk &amp; 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 &amp; cheese">
<input id="outputId" type="text">
const valueFromHiddenInput = $('#hiddenId').val();
const entityText = valueFromHiddenInput.replace(/&/g, '&amp;');
$('#outputId').val(entityText);

Execution trace:

  1. The browser parses value="chalk &amp; cheese".
  2. While parsing, it converts &amp; into the single character &.
  3. $('#hiddenId').val() returns "chalk & cheese".
  4. .replace(/&/g, '&amp;') creates the new JavaScript string "chalk &amp; cheese".
  5. .val(entityText) assigns that string directly as the text input's value.
  6. A text input does not parse its value as HTML, so it visibly shows chalk &amp; 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 &amp; Jerry in 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.
Take Quiz

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;amp;.

Common Mistakes

Expecting source entities to remain in the DOM

<input value="chalk &amp; 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, '&amp;');

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, '&amp;');
const twice = once.replace(/&/g, '&amp;');

console.log(twice); // "chalk &amp;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

TaskRecommended APIDoes the browser parse the string as HTML?
Read a form control's current value$('#id').val() / element.valueNo
Set a form control's displayed value$('#id').val(value) / element.value = valueNo
Display plain text in an element$('#id').text(value) / element.textContent = valueNo
Insert markup intentionally$('#id').html(markup) / element.innerHTML = markupYes
Read the default HTML attribute value$('#id').attr('value')The original attribute was already parsed

&amp; versus &:

RepresentationMeaning
&amp; in HTML sourceA safe HTML character reference for &
& in a JavaScript stringThe actual ampersand character
&amp; in a JavaScript string assigned with .val()Five literal characters shown in the input
&amp; inserted through innerHTMLParsed and displayed as &
Take Quiz

Cheat Sheet

  • HTML parsing converts &amp; 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 &amp; cheese') to show literal &amp; in a text input.
  • Use textContent or jQuery .text() to display untrusted text in ordinary elements.
  • Avoid .html() / innerHTML for 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, '&amp;');

$('#output').val(encodeAmpersands($('#hiddenId').val()));

FAQ

Why does JavaScript change &amp; into &?

JavaScript is reading the parsed DOM value. The browser decoded &amp; 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 &amp; literally?

Assign a JavaScript string containing those literal characters with .val():

$('#output').val('chalk &amp; 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, &amp;, &#38;, 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.

Take Quiz

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 &amp;. 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.

Take Quiz

Keep learning

Related questions

View more