diff --git a/addons/html_builder/static/src/core/utils/update_on_img_changed.js b/addons/html_builder/static/src/core/utils/update_on_img_changed.js
new file mode 100644
index 0000000000000..04606f19cf4e1
--- /dev/null
+++ b/addons/html_builder/static/src/core/utils/update_on_img_changed.js
@@ -0,0 +1,69 @@
+import { Component, onWillStart, xml } from "@odoo/owl";
+import { useDomState } from "../utils";
+
+class LoadImgComponent extends Component {
+ static template = xml`
+
+ `;
+ static props = { slots: { type: Object } };
+
+ setup() {
+ onWillStart(async () => {
+ const editingElements = this.env.getEditingElements();
+ const promises = [];
+ for (const editingEl of editingElements) {
+ const imageEls = editingEl.matches("img")
+ ? [editingEl]
+ : editingEl.querySelectorAll("img");
+ for (const imageEl of imageEls) {
+ if (!imageEl.complete) {
+ promises.push(
+ new Promise((resolve) => {
+ imageEl.addEventListener("load", () => resolve());
+ })
+ );
+ }
+ }
+ }
+ await Promise.all(promises);
+ });
+ }
+}
+
+/**
+ * In Chrome, when replacing an image on the DOM, some image properties are not
+ * available even if the image has been loaded beforehand. This is a problem if
+ * an option is using one of those property at each DOM change (useDomState).
+ * To solve the problem, this component reloads the option (and waits for the
+ * images to be loaded) each time an image has been modified inside its editing
+ * element.
+ */
+export class UpdateOptionOnImgChanged extends Component {
+ // TODO: this is a hack until is
+ // fixed in OWL.
+ static template = xml`
+
+
+ `;
+ static props = { slots: { type: Object } };
+ static components = { LoadImgComponent };
+
+ setup() {
+ let boolean = true;
+ this.state = useDomState((editingElement) => {
+ const imageEls = editingElement.matches("img")
+ ? [editingElement]
+ : editingElement.querySelectorAll("img");
+ for (const imageEl of imageEls) {
+ if (!imageEl.complete) {
+ // Rerender the slot if an image is not loaded
+ boolean = !boolean;
+ break;
+ }
+ }
+ return {
+ bool: boolean,
+ };
+ });
+ }
+}
diff --git a/addons/html_builder/static/src/website_builder/plugins/options/card_option.js b/addons/html_builder/static/src/website_builder/plugins/options/card_option.js
index 96c2329150b89..4525a667da4fc 100644
--- a/addons/html_builder/static/src/website_builder/plugins/options/card_option.js
+++ b/addons/html_builder/static/src/website_builder/plugins/options/card_option.js
@@ -3,6 +3,7 @@ import { WebsiteBackgroundOption } from "@html_builder/website_builder/plugins/o
import { CardImageOption } from "./card_image_option";
import { BorderConfigurator } from "@html_builder/plugins/border_configurator_option";
import { ShadowOption } from "@html_builder/plugins/shadow_option";
+import { UpdateOptionOnImgChanged } from "@html_builder/core/utils/update_on_img_changed";
export class CardOption extends BaseOptionComponent {
static template = "website.CardOption";
@@ -11,6 +12,7 @@ export class CardOption extends BaseOptionComponent {
WebsiteBackgroundOption,
BorderConfigurator,
ShadowOption,
+ UpdateOptionOnImgChanged,
};
static props = {
disableWidth: { type: Boolean, optional: true },
diff --git a/addons/html_builder/static/src/website_builder/plugins/options/card_option.xml b/addons/html_builder/static/src/website_builder/plugins/options/card_option.xml
index 4332aa361e8aa..37f702adb8b1e 100644
--- a/addons/html_builder/static/src/website_builder/plugins/options/card_option.xml
+++ b/addons/html_builder/static/src/website_builder/plugins/options/card_option.xml
@@ -11,7 +11,9 @@
-
+
+
+