Skip to content

Commit 1c2df76

Browse files
authored
Merge pull request #7369 from QwikDev/v2-input-value-escaping
fix: don't escape value attribute
2 parents b50948d + 61f6f64 commit 1c2df76

File tree

3 files changed

+54
-2
lines changed

3 files changed

+54
-2
lines changed

.changeset/afraid-garlics-greet.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@qwik.dev/core': patch
3+
---
4+
5+
fix: don't escape value attribute

packages/qwik/src/core/client/vnode.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,6 @@ import { qwikDebugToString } from '../debug';
122122
import { assertDefined, assertEqual, assertFalse, assertTrue } from '../shared/error/assert';
123123
import { QError, qError } from '../shared/error/error';
124124
import { DEBUG_TYPE, QContainerValue, VirtualType, VirtualTypeName } from '../shared/types';
125-
import { escapeHTML } from '../shared/utils/character-escaping';
126125
import { isText } from '../shared/utils/element';
127126
import {
128127
ELEMENT_ID,
@@ -912,7 +911,7 @@ export const vnode_applyJournal = (journal: VNodeJournal) => {
912911
if (isBooleanAttr(element, key)) {
913912
(element as any)[key] = parseBoolean(value);
914913
} else if (key === 'value' && key in element) {
915-
(element as any).value = escapeHTML(String(value));
914+
(element as any).value = String(value);
916915
} else if (key === dangerouslySetInnerHTML) {
917916
(element as any).innerHTML = value!;
918917
} else {

packages/qwik/src/core/tests/component.spec.tsx

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,54 @@ describe.each([
526526
}
527527
});
528528

529+
it('should not escape input value', async () => {
530+
const Cmp = component$(() => {
531+
const test = useSignal<string>();
532+
533+
return (
534+
<div>
535+
<input
536+
type="text"
537+
value={test.value}
538+
onInput$={$((_, element) => {
539+
test.value = element.value;
540+
})}
541+
/>
542+
543+
<p>{test.value}</p>
544+
</div>
545+
);
546+
});
547+
548+
const { vNode, document } = await render(<Cmp />, { debug });
549+
expect(vNode).toMatchVDOM(
550+
<Component ssr-required>
551+
<div>
552+
<input type="text" />
553+
<p>
554+
<Signal ssr-required></Signal>
555+
</p>
556+
</div>
557+
</Component>
558+
);
559+
560+
// simulate input
561+
const input = document.querySelector('input')!;
562+
input.value = "'";
563+
await trigger(document.body, input, 'input');
564+
565+
expect(vNode).toMatchVDOM(
566+
<Component ssr-required>
567+
<div>
568+
<input type="text" value="'" />
569+
<p>
570+
<Signal ssr-required>'</Signal>
571+
</p>
572+
</div>
573+
</Component>
574+
);
575+
});
576+
529577
it('should render correctly text node in the middle', async () => {
530578
const Cmp = component$(() => {
531579
const signal = useSignal<number>(0);

0 commit comments

Comments
 (0)