diff --git a/.changeset/perfect-ants-allow.md b/.changeset/perfect-ants-allow.md new file mode 100644 index 0000000000..0d4e5a05bf --- /dev/null +++ b/.changeset/perfect-ants-allow.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: set strings as attributes, non-strings as properties if property exists diff --git a/packages/svelte/src/internal/client/dom/elements/attributes.js b/packages/svelte/src/internal/client/dom/elements/attributes.js index 38b584b40c..7a0e86efa0 100644 --- a/packages/svelte/src/internal/client/dom/elements/attributes.js +++ b/packages/svelte/src/internal/client/dom/elements/attributes.js @@ -81,8 +81,6 @@ export function set_checked(element, checked) { * @param {boolean} [skip_warning] */ export function set_attribute(element, attribute, value, skip_warning) { - value = value == null ? null : value + ''; - // @ts-expect-error var attributes = (element.__attributes ??= {}); @@ -95,7 +93,7 @@ export function set_attribute(element, attribute, value, skip_warning) { (attribute === 'href' && element.nodeName === 'LINK') ) { if (!skip_warning) { - check_src_in_dev_hydration(element, attribute, value); + check_src_in_dev_hydration(element, attribute, value ?? ''); } // If we reset these attributes, they would result in another network request, which we want to avoid. @@ -113,10 +111,15 @@ export function set_attribute(element, attribute, value, skip_warning) { element[LOADING_ATTR_SYMBOL] = value; } - if (value === null) { + if (value == null) { element.removeAttribute(attribute); } else { - element.setAttribute(attribute, value); + if (attribute in element && typeof value !== 'string') { + // @ts-ignore + element[attribute] = value; + } else { + element.setAttribute(attribute, value); + } } } @@ -287,15 +290,15 @@ export function set_attributes( name = normalize_attribute(name); } - if (setters.includes(name)) { + if (setters.includes(name) && typeof value !== 'string') { + // @ts-ignore + element[name] = value; + } else if (typeof value !== 'function') { if (hydrating && (name === 'src' || name === 'href' || name === 'srcset')) { - if (!skip_warning) check_src_in_dev_hydration(element, name, value); + if (!skip_warning) check_src_in_dev_hydration(element, name, value ?? ''); } else { - // @ts-ignore - element[name] = value; + set_attribute(element, name, value); } - } else if (typeof value !== 'function') { - set_attribute(element, name, value); } } } @@ -389,12 +392,12 @@ function get_setters(element) { /** * @param {any} element * @param {string} attribute - * @param {string | null} value + * @param {string} value */ function check_src_in_dev_hydration(element, attribute, value) { if (!DEV) return; if (attribute === 'srcset' && srcset_url_equal(element, value)) return; - if (src_url_equal(element.getAttribute(attribute) ?? '', value ?? '')) return; + if (src_url_equal(element.getAttribute(attribute) ?? '', value)) return; w.hydration_attribute_changed( attribute, @@ -420,12 +423,12 @@ function split_srcset(srcset) { /** * @param {HTMLSourceElement | HTMLImageElement} element - * @param {string | undefined | null} srcset + * @param {string} srcset * @returns {boolean} */ function srcset_url_equal(element, srcset) { var element_urls = split_srcset(element.srcset); - var urls = split_srcset(srcset ?? ''); + var urls = split_srcset(srcset); return ( urls.length === element_urls.length && diff --git a/packages/svelte/tests/runtime-runes/samples/attribute-if-string/_config.js b/packages/svelte/tests/runtime-runes/samples/attribute-if-string/_config.js new file mode 100644 index 0000000000..990a5a6ab8 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/attribute-if-string/_config.js @@ -0,0 +1,21 @@ +import { test } from '../../test'; + +export default test({ + test({ assert, target }) { + const should_be_false = /** @type {HTMLDivElement[]} */ ( + target.querySelectorAll('.translate-false div') + ); + + const should_be_true = /** @type {HTMLDivElement[]} */ ( + target.querySelectorAll('.translate-true div') + ); + + should_be_false.forEach((div, i) => { + assert.equal(div.translate, false, `${i + 1} of ${should_be_false.length}: ${div.outerHTML}`); + }); + + should_be_true.forEach((div, i) => { + assert.equal(div.translate, true, `${i + 1} of ${should_be_true.length}: ${div.outerHTML}`); + }); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/attribute-if-string/main.svelte b/packages/svelte/tests/runtime-runes/samples/attribute-if-string/main.svelte new file mode 100644 index 0000000000..7696f4e78d --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/attribute-if-string/main.svelte @@ -0,0 +1,19 @@ +
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+