diff --git a/NEWS.rst b/NEWS.rst
index c017b4fda42e9125d699bd8002459b78b0c8b1ad_TkVXUy5yc3Q=..b9c9c1f941fecdfb44fcd4b198e1825f30f8d261_TkVXUy5yc3Q= 100644
--- a/NEWS.rst
+++ b/NEWS.rst
@@ -2,6 +2,11 @@
 Changelog
 =========
 
+18.0.1.1.0
+----------
+
+Add dynamic expression button for substitution line and new converter features.
+
 18.0.1.0.5
 ----------
 
diff --git a/__manifest__.py b/__manifest__.py
index c017b4fda42e9125d699bd8002459b78b0c8b1ad_X19tYW5pZmVzdF9fLnB5..b9c9c1f941fecdfb44fcd4b198e1825f30f8d261_X19tYW5pZmVzdF9fLnB5 100644
--- a/__manifest__.py
+++ b/__manifest__.py
@@ -21,7 +21,7 @@
 {
     "name": "Redner",
     "license": "AGPL-3",
-    "version": "18.0.1.0.5",
+    "version": "18.0.1.1.0",
     "category": "Reporting",
     "author": "XCG Consulting",
     "website": "https://orbeet.io/",
@@ -30,7 +30,6 @@
     "data": [
         "wizard/mail_compose_message_views.xml",
         "wizard/template_list_view.xml",
-        "wizard/expression_builder_view.xml",
         "security/ir.model.access.csv",
         "views/redner_template.xml",
         "views/mail_template.xml",
@@ -38,7 +37,10 @@
         "views/menu.xml",
     ],
     "assets": {
-        "web.assets_backend": ["redner/static/src/js/redner_report_action.esm.js"],
+        "web.assets_backend": [
+            "redner/static/src/js/redner_report_action.esm.js",
+            "redner/static/src/components/**/*",
+        ],
     },
     "installable": True,
     "external_dependencies": {"python": ["requests_unixsocket", "python-magic"]},
diff --git a/i18n/fr.po b/i18n/fr.po
index c017b4fda42e9125d699bd8002459b78b0c8b1ad_aTE4bi9mci5wbw==..b9c9c1f941fecdfb44fcd4b198e1825f30f8d261_aTE4bi9mci5wbw== 100644
--- a/i18n/fr.po
+++ b/i18n/fr.po
@@ -6,8 +6,8 @@
 msgstr ""
 "Project-Id-Version: Odoo Server 18.0\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2024-09-05 08:41+0000\n"
-"PO-Revision-Date: 2024-11-18 09:26+0000\n"
+"POT-Creation-Date: 2024-12-18 16:34+0000\n"
+"PO-Revision-Date: 2024-12-18 16:36+0000\n"
 "Last-Translator: Axel PREL <axel.prel@xcg-consulting.fr>\n"
 "Language-Team: XCG Consulting\n"
 "Language: fr\n"
@@ -15,8 +15,8 @@
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n > 1);\n"
-"X-Generator: Poedit 3.0.1\n"
+"X-Generator: Poedit 3.5\n"
 
 #. module: redner
 #. odoo-python
 #: code:addons/redner/models/redner_template.py:0
@@ -19,11 +19,10 @@
 
 #. module: redner
 #. odoo-python
 #: code:addons/redner/models/redner_template.py:0
-#, python-format
 msgid "%s (copy)"
 msgstr "%s (copie)"
 
 #. module: redner
 #. odoo-python
 #: code:addons/redner/models/ir_actions_report.py:0
@@ -24,10 +23,9 @@
 msgid "%s (copy)"
 msgstr "%s (copie)"
 
 #. module: redner
 #. odoo-python
 #: code:addons/redner/models/ir_actions_report.py:0
-#, python-format
 msgid "(Native)"
 msgstr "(Natif)"
 
@@ -49,10 +47,9 @@
 #. module: redner
 #. odoo-python
 #: code:addons/redner/redner.py:0
-#, python-format
 msgid "Cannot Establish a connection to server"
 msgstr "La connexion au serveur ne peut pas être établie"
 
 #. module: redner
 #. odoo-python
 #: code:addons/redner/redner.py:0
@@ -53,11 +50,10 @@
 msgid "Cannot Establish a connection to server"
 msgstr "La connexion au serveur ne peut pas être établie"
 
 #. module: redner
 #. odoo-python
 #: code:addons/redner/redner.py:0
-#, python-format
 msgid ""
 "Cannot find redner config url. Please add it in odoo.conf or in ir."
 "config_parameter"
 msgstr ""
@@ -60,9 +56,9 @@
 msgid ""
 "Cannot find redner config url. Please add it in odoo.conf or in ir."
 "config_parameter"
 msgstr ""
-"La configuration de l'url de Redner est introuvable. Merci de l'ajouter "
-"dans le fichier odoo.conf ou dans ir.config.parameter"
+"La configuration de l'url de Redner est introuvable. Merci de l'ajouter dans "
+"le fichier odoo.conf ou dans ir.config.parameter"
 
 #. module: redner
 #: model:ir.model.fields,help:redner.field_redner_template__body
@@ -121,6 +117,11 @@
 msgstr "Nom à afficher"
 
 #. module: redner
+#: model:ir.model.fields,field_description:redner.field_redner_substitution__dynamic_placeholder_button_hidden
+msgid "Dynamic Placeholder Button Hidden"
+msgstr "Dynamic Placeholder Button Hidden"
+
+#. module: redner
 #: model:ir.model.fields,field_description:redner.field_redner_substitution__template_id
 msgid "Email Template"
 msgstr "Modèle de courriel"
@@ -148,8 +149,7 @@
 #. module: redner
 #. odoo-python
 #: code:addons/redner/models/redner_template.py:0
-#, python-format
-msgid "Failed to update render template, %s"
+msgid "Failed to update Redner template, %s"
 msgstr "Échec de la mise à jour du modèle redner, %s"
 
 #. module: redner
@@ -160,7 +160,6 @@
 #. module: redner
 #. odoo-python
 #: code:addons/redner/models/ir_actions_report.py:0
-#, python-format
 msgid "Field 'Output Format' is required for Redner report"
 msgstr "Le champ 'Format de sortie' est requis pour le rapport Redner"
 
@@ -210,9 +209,8 @@
 #: model:ir.model.fields,help:redner.field_ir_actions_report__redner_multi_in_one
 msgid ""
 "If you execute a report on several records, by default Odoo will generate a "
-"ZIP file that contains as many files as selected records. If you enable "
-"this option, Odoo will generate instead a single report for the selected "
-"records."
+"ZIP file that contains as many files as selected records. If you enable this "
+"option, Odoo will generate instead a single report for the selected records."
 msgstr ""
 "Si vous exécutez un rapport sur plusieurs enregistrements, par défaut, Odoo "
 "générera un fichier ZIP qui contiendra autant de fichiers que "
@@ -237,7 +235,7 @@
 #. module: redner
 #: model:ir.model.fields,field_description:redner.field_redner_report__ir_actions_report_id
 msgid "Ir Actions Report"
-msgstr ""
+msgstr "Ir Actions Report"
 
 #. module: redner
 #: model:ir.model.fields,field_description:redner.field_redner_template__is_mjml
@@ -256,6 +254,7 @@
 msgstr "Les mots-clés vont être mis à jour. Continuer ?"
 
 #. module: redner
+#: model:ir.model.fields,field_description:redner.field_redner_substitution__lang
 #: model:ir.model.fields,field_description:redner.field_redner_template__language
 msgid "Language"
 msgstr "Langage"
@@ -282,6 +281,11 @@
 msgstr "Modèle LibreOffice"
 
 #. module: redner
+#: model:ir.model.fields,field_description:redner.field_redner_template__template_data_filename
+msgid "Libreoffice Template Filename"
+msgstr "Nom de fichier du modèle LibreOffice"
+
+#. module: redner
 #: model:ir.model.fields,field_description:redner.field_redner_template__locale_id
 msgid "Locale"
 msgstr "Localisation"
@@ -297,6 +301,12 @@
 msgstr "Plusieurs enregistrements dans un seul rapport Redner"
 
 #. module: redner
+#. odoo-python
+#: code:addons/redner/models/redner_substitution.py:0
+msgid "N/A"
+msgstr "N/A"
+
+#. module: redner
 #: model:ir.model.fields,field_description:redner.field_redner_template__name
 #: model:ir.model.fields,field_description:redner.field_template_list_wizard__name
 msgid "Name"
@@ -310,7 +320,7 @@
 #. module: redner
 #: model:ir.model.fields.selection,name:redner.selection__redner_template__source__odoo
 msgid "Odoo"
-msgstr ""
+msgstr "Odoo"
 
 #. module: redner
 #: model:ir.model.fields.selection,name:redner.selection__redner_substitution__converter__mail_template
@@ -328,6 +338,15 @@
 msgstr "OpenDocument + mustache"
 
 #. module: redner
+#: model:ir.model.fields,help:redner.field_redner_substitution__lang
+msgid ""
+"Optional translation language (ISO code) to select when sending out an "
+"email. If not set, the english version will be used. This should usually be "
+"a placeholder expression that provides the appropriate language, e.g. "
+"{{ object.partner_id.lang }}."
+msgstr ""
+
+#. module: redner
 #: model:ir.model.fields,help:redner.field_redner_template__locale_id
 msgid "Optional translation language (ISO code)."
 msgstr "Langue de traduction facultative (code ISO)."
@@ -381,6 +400,11 @@
 msgstr "Action du rapport redner introuvable pour le rapport %s"
 
 #. module: redner
+#: model:ir.model.fields,field_description:redner.field_redner_substitution__model
+msgid "Related Report Model"
+msgstr "Modèle de Rapport Associé"
+
+#. module: redner
 #: model:ir.model.fields.selection,name:redner.selection__redner_substitution__converter__relation-path
 msgid "Relation Path"
 msgstr "Chemin relationnel"
@@ -397,6 +421,11 @@
 msgstr "Rendu par Redner"
 
 #. module: redner
+#: model:ir.model.fields,field_description:redner.field_redner_substitution__render_model
+msgid "Rendering Model"
+msgstr "Modèle de rendu"
+
+#. module: redner
 #: model:ir.model.fields,field_description:redner.field_redner_substitution__ir_actions_report_id
 msgid "Report"
 msgstr "Rapport"
@@ -440,7 +469,7 @@
 #: model:ir.model.fields,help:redner.field_redner_template__source
 msgid "Source of the template, created in Odoo or imported from Redner."
 msgstr ""
-"La source du modèle, si il a été créé dans Odoo ou importé depuis Redner"
+"La source du modèle, si il a été créé dans Odoo ou importé depuis Redner."
 
 #. module: redner
 #: model:ir.model.fields,field_description:redner.field_ir_actions_report__substitution_ids
@@ -490,5 +519,14 @@
 msgstr "La prévisualisation en PNG du modèle"
 
 #. module: redner
+#: model:ir.model.fields,help:redner.field_redner_template__name
+msgid ""
+"The name of the template. Once the template is created, updating the name is "
+"not allowed. To change the name, delete the template and create a new one."
+msgstr ""
+"Le nom du modèle. Une fois le modèle créé, la mise à jour du nom n'est pas "
+"autorisée. Pour modifier le nom, supprimez le modèle et créez-en un nouveau."
+
+#. module: redner
 #. odoo-python
 #: code:addons/redner/models/ir_actions_report.py:0
@@ -493,6 +531,5 @@
 #. odoo-python
 #: code:addons/redner/models/ir_actions_report.py:0
-#, python-format
 msgid ""
 "The output format cannot be different from the extension defined in \"Save "
 "as attachment prefix\"."
@@ -508,15 +545,10 @@
 "browser PDF means the report will be rendered using Wkhtmltopdf and "
 "downloaded by the user."
 msgstr ""
-"Le type de rapport qui va être rendu, chaque type ayant sa propre méthode "
-"de rendu. \"HTML\" signifie que le rapport sera ouvert directement dans le "
-"navigateur. \"PDF\" signifie que le rapport va être rendu par Wkhtmltopdf "
-"et ensuite téléchargé par l'utilisateur."
-
-#. module: redner
-#: model:ir.model.fields,help:redner.field_redner_template__name
-msgid "This is a name of template mjml redner"
-msgstr "C'est le nom du template mjml redner"
+"Le type de rapport qui va être rendu, chaque type ayant sa propre méthode de "
+"rendu. \"HTML\" signifie que le rapport sera ouvert directement dans le "
+"navigateur. \"PDF\" signifie que le rapport va être rendu par Wkhtmltopdf et "
+"ensuite téléchargé par l'utilisateur."
 
 #. module: redner
 #: model:ir.model.fields,help:redner.field_redner_template__preview
@@ -525,4 +557,12 @@
 
 #. module: redner
 #. odoo-python
+#: code:addons/redner/models/redner_template.py:0
+msgid ""
+"Unable to update the template data. Please check the logs for more details."
+msgstr ""
+"Unable to update the template data. Please check the logs for more details."
+
+#. module: redner
+#. odoo-python
 #: code:addons/redner/redner.py:0
@@ -528,6 +568,5 @@
 #: code:addons/redner/redner.py:0
-#, python-format
 msgid "Unexpected redner error: %r"
 msgstr "Erreur redner : %r"
 
 #. module: redner
@@ -530,7 +569,12 @@
 msgid "Unexpected redner error: %r"
 msgstr "Erreur redner : %r"
 
 #. module: redner
+#: model:ir.model.fields,field_description:redner.field_redner_substitution__value_placeholder
+msgid "Value Placeholder"
+msgstr "Placeholder de l'expresion"
+
+#. module: redner
 #: model:ir.model.fields,field_description:redner.field_redner_substitution__keyword
 msgid "Variable"
 msgstr "Variable"
@@ -550,7 +594,6 @@
 #. odoo-python
 #: code:addons/redner/models/mail_template.py:0
 #: code:addons/redner/models/redner_report.py:0
-#, python-format
 msgid ""
 "We received an unexpected error from redner server. Please contact your "
 "administrator"
@@ -561,7 +604,42 @@
 #. module: redner
 #. odoo-python
 #: code:addons/redner/models/redner_substitution.py:0
-#, python-format
+msgid "e.g: name or partner_id.name"
+msgstr "par ex. name or partner_id.name"
+
+#. module: redner
+#. odoo-python
+#: code:addons/redner/models/redner_substitution.py:0
+msgid "e.g: partner_id/category_id/name ou partner_id/child_ids[]"
+msgstr "par ex. partner_id/category_id/name ou partner_id/child_ids[]"
+
+#. module: redner
+#. odoo-python
+#: code:addons/redner/models/redner_substitution.py:0
+msgid "e.g: tax_ids"
+msgstr "par ex. tax_ids"
+
+#. module: redner
+#. odoo-python
+#: code:addons/redner/models/redner_substitution.py:0
+msgid "e.g: {{ object.get_partner_info() | safe }}"
+msgstr "par ex. {{ object.get_partner_info() | safe }}"
+
+#. module: redner
+#. odoo-python
+#: code:addons/redner/models/redner_substitution.py:0
+msgid "e.g: {{object.partner_id.name}}"
+msgstr "par ex. {{object.partner_id.name}}"
+
+#. module: redner
+#. odoo-python
+#: code:addons/redner/models/redner_substitution.py:0
+msgid "e.g: www.orbeet.io"
+msgstr "par ex. www.orbeet.io"
+
+#. module: redner
+#. odoo-python
+#: code:addons/redner/models/redner_substitution.py:0
 msgid "invalid converter type: %s"
 msgstr "type de convertisseur invalide : %s"
 
@@ -579,10 +657,3 @@
 #: model:ir.model.fields,help:redner.field_redner_template__language
 msgid "templating language"
 msgstr "langage du modèle"
-
-#. module: redner
-#: model:ir.model.fields,field_description:redner.field_redner_report____last_update
-#: model:ir.model.fields,field_description:redner.field_redner_substitution____last_update
-#: model:ir.model.fields,field_description:redner.field_redner_template____last_update
-msgid "Last Modified on"
-msgstr "Dernière modification le"
diff --git a/models/redner_substitution.py b/models/redner_substitution.py
index c017b4fda42e9125d699bd8002459b78b0c8b1ad_bW9kZWxzL3JlZG5lcl9zdWJzdGl0dXRpb24ucHk=..b9c9c1f941fecdfb44fcd4b198e1825f30f8d261_bW9kZWxzL3JlZG5lcl9zdWJzdGl0dXRpb24ucHk= 100644
--- a/models/redner_substitution.py
+++ b/models/redner_substitution.py
@@ -25,8 +25,34 @@
 from ..converter import ImageDataURL, ImageFile
 from ..utils.sorting import parse_sorted_field, sortkey
 
+FIELD = "field"
+CONSTANT = "constant"
+MAIL_TEMPLATE = "mail_template"
+MAIL_TEMPLATE_DESERIALIZE = "mail_template+deserialize"
+IMAGE_FILE = "image-file"
+IMAGE_DATAURL = "image-data-url"
+RELATION_2MANY = "relation-to-many"
+RELATION_PATH = "relation-path"
+
+CONVERTER_SELECTION = [
+    (MAIL_TEMPLATE, "Odoo Template"),
+    (MAIL_TEMPLATE_DESERIALIZE, "Odoo Template + Eval"),
+    (FIELD, "Field"),
+    (IMAGE_FILE, "Image file"),
+    (IMAGE_DATAURL, "Image data url"),
+    (RELATION_2MANY, "Relation to many"),
+    (RELATION_PATH, "Relation Path"),
+    (CONSTANT, "Constant value"),
+]
+
+DYNAMIC_PLACEHOLDER_ALLOWED_CONVERTERS = (
+    FIELD,
+    MAIL_TEMPLATE,
+    MAIL_TEMPLATE_DESERIALIZE,
+)
+
 
 class Substitution(models.Model):
     """Substitution values for a Redner email message"""
 
     _name = "redner.substitution"
@@ -28,8 +54,9 @@
 
 class Substitution(models.Model):
     """Substitution values for a Redner email message"""
 
     _name = "redner.substitution"
+    _inherit = ["mail.render.mixin"]
     _description = "Redner Substitution"
 
     keyword = fields.Char(string="Variable", help="Template variable name")
@@ -40,5 +67,13 @@
         comodel_name="ir.actions.report", string="Report"
     )
 
+    model = fields.Char(
+        "Related Report Model",
+        related="ir_actions_report_id.model",
+        index=True,
+        store=True,
+        readonly=True,
+    )
+
     value = fields.Char(string="Expression")
 
@@ -43,15 +78,12 @@
     value = fields.Char(string="Expression")
 
-    converter = fields.Selection(
-        selection=[
-            ("mail_template", "Odoo Template"),
-            ("mail_template+deserialize", "Odoo Template + Eval"),
-            ("field", "Field"),
-            ("image-file", "Image file"),
-            ("image-data-url", "Image data url"),
-            ("relation-to-many", "Relation to many"),
-            ("relation-path", "Relation Path"),
-            ("constant", "Constant value"),
-        ]
+    converter = fields.Selection(selection=CONVERTER_SELECTION)
+
+    depth = fields.Integer(string="Depth", compute="_compute_depth", store=True)
+
+    value_placeholder = fields.Char(compute="_compute_value_placeholder")
+
+    dynamic_placeholder_button_hidden = fields.Boolean(
+        compute="_compute_dynamic_placeholder_button_hidden"
     )
 
@@ -56,9 +88,40 @@
     )
 
-    depth = fields.Integer(string="Depth", compute="_compute_depth", store=True)
+    @api.depends("converter")
+    def _compute_value_placeholder(self):
+        """Computes a dynamic placeholder that depends on the selected type
+        to help the user inputs their data.
+        """
+        for subsitution in self:
+            placeholder = _("N/A")
+            if subsitution.converter == FIELD:
+                placeholder = _("e.g: name or partner_id.name")
+            elif subsitution.converter == MAIL_TEMPLATE:
+                placeholder = _("e.g: {{object.partner_id.name}}")
+            elif subsitution.converter == MAIL_TEMPLATE_DESERIALIZE:
+                placeholder = _("e.g: {{ object.get_partner_info() | safe }}")
+            elif subsitution.converter == RELATION_2MANY:
+                placeholder = _("e.g: tax_ids")
+            elif subsitution.converter == RELATION_PATH:
+                placeholder = _(
+                    "e.g: partner_id/category_id/name ou partner_id/child_ids[]"
+                )
+            elif subsitution.converter == CONSTANT:
+                placeholder = _("e.g: www.orbeet.io")
+            subsitution.value_placeholder = placeholder
+
+    @api.depends("value")
+    def _compute_render_model(self):
+        for substitution in self:
+            if substitution.ir_actions_report_id:
+                substitution.render_model = substitution.model
+            elif substitution.template_id:
+                substitution.render_model = substitution.template_id.model_id.model
+            else:
+                substitution.render_model = False
 
     @api.depends("keyword")
     def _compute_depth(self):
         for record in self:
             record.depth = record.keyword.count(".")
 
@@ -59,9 +122,16 @@
 
     @api.depends("keyword")
     def _compute_depth(self):
         for record in self:
             record.depth = record.keyword.count(".")
 
+    @api.depends("converter")
+    def _compute_dynamic_placeholder_button_hidden(self):
+        for record in self:
+            record.dynamic_placeholder_button_hidden = (
+                record.converter not in DYNAMIC_PLACEHOLDER_ALLOWED_CONVERTERS
+            )
+
     def get_children(self):
         return self.search(
             [
@@ -119,40 +189,3 @@
             d[sub.keyword.rsplit(".", 2)[-1]] = conv
 
         return converter.Model("", d)
-
-    def action_build_expression(self):
-        if not (self and self.ir_actions_report_id):
-            if not self.template_id:
-                # neither a report nor a mail template
-                return
-            else:
-                model = self.env.get(self.template_id.model_id.model)
-        else:
-            model = self.env.get(self.ir_actions_report_id.model)
-        if model is None:
-            return
-
-        # reset the older substitution value
-        self.value = ""
-
-        wizard = self.env["expression.builder.wizard"].create(
-            {
-                "substitution_id": self.id,
-                "expression": "",
-            }
-        )
-
-        vals_list = wizard.get_fields(model, self.converter)
-        for val in vals_list:
-            val["wizard_id"] = wizard.id
-
-        fields_list = self.env["expression.builder.field"].create(vals_list)
-        wizard.suggested_fields = [(6, 0, fields_list.ids)]
-
-        return {
-            "type": "ir.actions.act_window",
-            "res_model": "expression.builder.wizard",
-            "view_mode": "form",
-            "res_id": wizard.id,
-            "target": "new",
-        }
diff --git a/security/ir.model.access.csv b/security/ir.model.access.csv
index c017b4fda42e9125d699bd8002459b78b0c8b1ad_c2VjdXJpdHkvaXIubW9kZWwuYWNjZXNzLmNzdg==..b9c9c1f941fecdfb44fcd4b198e1825f30f8d261_c2VjdXJpdHkvaXIubW9kZWwuYWNjZXNzLmNzdg== 100644
--- a/security/ir.model.access.csv
+++ b/security/ir.model.access.csv
@@ -3,5 +3,3 @@
 access_redner_template,access_redner_template,model_redner_template,base.group_no_one,1,1,1,1
 access_redner_substitution,access_redner_substitution,model_redner_substitution,base.group_no_one,1,1,1,1
 access_redner_template_list,access_redner_template_list,model_template_list_wizard,base.group_no_one,1,1,1,1
-access_redner_expression_builder,access_redner_expression_builder,model_expression_builder_wizard,base.group_no_one,1,1,1,1
-access_redner_expression_builder_field,access_redner_expression_builder_field,model_expression_builder_field,base.group_no_one,1,1,1,1
diff --git a/static/src/components/dynamic_placeholder_charfield/dynamic_placeholder_charfield_patch.js b/static/src/components/dynamic_placeholder_charfield/dynamic_placeholder_charfield_patch.js
new file mode 100644
index 0000000000000000000000000000000000000000..b9c9c1f941fecdfb44fcd4b198e1825f30f8d261_c3RhdGljL3NyYy9jb21wb25lbnRzL2R5bmFtaWNfcGxhY2Vob2xkZXJfY2hhcmZpZWxkL2R5bmFtaWNfcGxhY2Vob2xkZXJfY2hhcmZpZWxkX3BhdGNoLmpz
--- /dev/null
+++ b/static/src/components/dynamic_placeholder_charfield/dynamic_placeholder_charfield_patch.js
@@ -0,0 +1,69 @@
+/** @odoo-module **/
+
+import {CharField, charField} from "@web/views/fields/char/char_field";
+import {patch} from "@web/core/utils/patch";
+
+// Adding a new property for dynamic placeholder button visibility
+CharField.props = {
+    ...CharField.props,
+    dynamicPlaceholderButtonField: {type: String, optional: true},
+    dynamicPlaceholderConverterField: {type: String, optional: true},
+};
+
+// Extending charField to extract the new property
+const charExtractProps = charField.extractProps;
+charField.extractProps = (fieldInfo) => {
+    return Object.assign(charExtractProps(fieldInfo), {
+        dynamicPlaceholderButtonField:
+            fieldInfo.options?.dynamic_placeholder_button_field,
+        dynamicPlaceholderConverterField:
+            fieldInfo.options?.dynamic_placeholder_converter_field,
+    });
+};
+
+// Patching CharField to include the visibility check
+patch(CharField.prototype, {
+    setup() {
+        super.setup();
+    },
+    get hasDynamicPlaceholderButton() {
+        return !this.props.record.data[this.props.dynamicPlaceholderButtonField];
+    },
+    get converter() {
+        return (
+            this.props.record.data[this.props.dynamicPlaceholderConverterField] || ""
+        );
+    },
+    async onDynamicPlaceholderValidate(chain, defaultValue) {
+        if (chain) {
+            this.input.el.focus();
+            // Initialize dynamicPlaceholder with a default structure
+            let dynamicPlaceholder = ` {{object.${chain}${
+                defaultValue?.length ? ` ||| ${defaultValue}` : ""
+            }}}`;
+            switch (this.converter) {
+                case "field":
+                    // For "field" converter, use the chain directly as the value
+                    dynamicPlaceholder = `${chain}`;
+                    break;
+
+                default:
+                    // Default case if no specific converter type is found
+                    dynamicPlaceholder = ` {{object.${chain}${
+                        defaultValue?.length ? ` ||| ${defaultValue}` : ""
+                    }}}`;
+                    break;
+            }
+            this.input.el.setRangeText(
+                dynamicPlaceholder,
+                this.selectionStart,
+                this.selectionStart,
+                "end"
+            );
+            // trigger events to make the field dirty
+            this.input.el.dispatchEvent(new InputEvent("input"));
+            this.input.el.dispatchEvent(new KeyboardEvent("keydown"));
+            this.input.el.focus();
+        }
+    },
+});
diff --git a/static/src/components/dynamic_placeholder_charfield/dynamic_placeholder_charfield_patch.xml b/static/src/components/dynamic_placeholder_charfield/dynamic_placeholder_charfield_patch.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b9c9c1f941fecdfb44fcd4b198e1825f30f8d261_c3RhdGljL3NyYy9jb21wb25lbnRzL2R5bmFtaWNfcGxhY2Vob2xkZXJfY2hhcmZpZWxkL2R5bmFtaWNfcGxhY2Vob2xkZXJfY2hhcmZpZWxkX3BhdGNoLnhtbA==
--- /dev/null
+++ b/static/src/components/dynamic_placeholder_charfield/dynamic_placeholder_charfield_patch.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<templates xml:space="preserve">
+    <t t-inherit="web.CharField" t-inherit-mode="extension">
+        <xpath expr="//button[@t-if='hasDynamicPlaceholder']" position="attributes">
+            <attribute name="t-if">
+                hasDynamicPlaceholder and hasDynamicPlaceholderButton
+            </attribute>
+        </xpath>
+    </t>
+</templates>
diff --git a/views/ir_actions_report.xml b/views/ir_actions_report.xml
index c017b4fda42e9125d699bd8002459b78b0c8b1ad_dmlld3MvaXJfYWN0aW9uc19yZXBvcnQueG1s..b9c9c1f941fecdfb44fcd4b198e1825f30f8d261_dmlld3MvaXJfYWN0aW9uc19yZXBvcnQueG1s 100644
--- a/views/ir_actions_report.xml
+++ b/views/ir_actions_report.xml
@@ -43,12 +43,9 @@
                             <list editable="top" default_order="keyword asc">
                                 <field name="keyword" />
                                 <field name="converter" />
-                                <field name="value" />
-                                <button
-                                    name="action_build_expression"
-                                    type="object"
-                                    string="Build expression"
-                                    class="oe_highlight"
-                                    invisible="not (value and value!='') or not (converter and converter in ['field','relation-to-many'])"
-                                    confirm="This will delete the current substitution value. Continue anyway ?"
+                                <field name="render_model" column_invisible="1" />
+                                <field name="value_placeholder" column_invisible="1" />
+                                <field
+                                    name="dynamic_placeholder_button_hidden"
+                                    column_invisible="1"
                                 />
@@ -54,17 +51,16 @@
                                 />
-                                <button
-                                    name="action_build_expression"
-                                    type="object"
-                                    string="Build expression"
-                                    class="oe_highlight"
-                                    invisible="(value and value !='') or not (converter and converter in ['field','relation-to-many'])"
-                                />
-                                <button
-                                    name="action_build_expression"
-                                    type="object"
-                                    string="Build expression"
-                                    class="oe_highlight disabled"
-                                    invisible="converter in ['field','relation-to-many']"
+                                <field
+                                    name="value"
+                                    class="text-break"
+                                    required="converter != False"
+                                    options="{
+                                        'dynamic_placeholder': true, 
+                                        'dynamic_placeholder_model_reference_field': 'render_model', 
+                                        'placeholder_field': 'value_placeholder',
+                                        'dynamic_placeholder_button_field': 'dynamic_placeholder_button_hidden',
+                                        'dynamic_placeholder_converter_field': 'converter',
+                                    }"
+                                    default_focus="1"
                                 />
                             </list>
                         </field>
diff --git a/views/mail_template.xml b/views/mail_template.xml
index c017b4fda42e9125d699bd8002459b78b0c8b1ad_dmlld3MvbWFpbF90ZW1wbGF0ZS54bWw=..b9c9c1f941fecdfb44fcd4b198e1825f30f8d261_dmlld3MvbWFpbF90ZW1wbGF0ZS54bWw= 100644
--- a/views/mail_template.xml
+++ b/views/mail_template.xml
@@ -39,12 +39,9 @@
                         <list editable="top" default_order="keyword asc">
                             <field name="keyword" />
                             <field name="converter" />
-                            <field name="value" />
-                            <button
-                                name="action_build_expression"
-                                type="object"
-                                string="Build expression"
-                                class="oe_highlight"
-                                invisible="not (value and value!='') or not (converter and converter in ['field','relation-to-many'])"
-                                confirm="This will delete the current substitution value. Continue anyway ?"
+                            <field name="render_model" column_invisible="1" />
+                            <field name="value_placeholder" column_invisible="1" />
+                            <field
+                                name="dynamic_placeholder_button_hidden"
+                                column_invisible="1"
                             />
@@ -50,17 +47,16 @@
                             />
-                            <button
-                                name="action_build_expression"
-                                type="object"
-                                string="Build expression"
-                                class="oe_highlight"
-                                invisible="(value and value !='') or not (converter and converter in ['field','relation-to-many'])"
-                            />
-                            <button
-                                name="action_build_expression"
-                                type="object"
-                                string="Build expression"
-                                class="oe_highlight disabled"
-                                invisible="converter in ['field','relation-to-many']"
+                            <field
+                                name="value"
+                                class="text-break"
+                                required="converter != False"
+                                options="{
+                                    'dynamic_placeholder': true,
+                                    'dynamic_placeholder_model_reference_field': 'render_model'
+                                    'placeholder_field': 'value_placeholder',
+                                    'dynamic_placeholder_button_field': 'dynamic_placeholder_button_hidden',
+                                    'dynamic_placeholder_converter_field': 'converter',
+                                }"
+                                default_focus="1"
                             />
                         </list>
                     </field>
diff --git a/wizard/__init__.py b/wizard/__init__.py
index c017b4fda42e9125d699bd8002459b78b0c8b1ad_d2l6YXJkL19faW5pdF9fLnB5..b9c9c1f941fecdfb44fcd4b198e1825f30f8d261_d2l6YXJkL19faW5pdF9fLnB5 100644
--- a/wizard/__init__.py
+++ b/wizard/__init__.py
@@ -1,6 +1,4 @@
 from . import (
-    expression_builder,
-    expression_builder_field,
     mail_compose_message,
     template_list,
 )
diff --git a/wizard/expression_builder.py b/wizard/expression_builder.py
deleted file mode 100644
index c017b4fda42e9125d699bd8002459b78b0c8b1ad_d2l6YXJkL2V4cHJlc3Npb25fYnVpbGRlci5weQ==..0000000000000000000000000000000000000000
--- a/wizard/expression_builder.py
+++ /dev/null
@@ -1,128 +0,0 @@
-from odoo import exceptions, fields, models
-
-
-# ExpressionBuilder
-class ExpressionBuilder(models.TransientModel):
-    _name = "expression.builder.wizard"
-    _description = "Expression Builder Wizard"
-
-    # the substitution the expression builder is working on
-    substitution_id = fields.Many2one(
-        comodel_name="redner.substitution",
-        string="Substitution",
-        help="The Redner Substitution on which we assign the value",
-        required=True,
-    )
-    # the expression field is concatened with the fields values
-    # when the wizard action is completed, this field is
-    # written in the substitution value
-    expression = fields.Char(
-        string="Substitution",
-        help=(
-            "Stores the substitution value the builder is working on."
-            " (example: 'partner_id.name')"
-        ),
-    )
-
-    suggested_fields = fields.One2many(
-        comodel_name="expression.builder.field",
-        inverse_name="wizard_id",
-        string="Suggested Fields",
-        help="The suggested fields, based on the substitution converter value",
-    )
-
-    def get_fields(self, model, converter):
-        # Get all field records for the model
-        vals_list = self.env["ir.model.fields"].search([("model", "=", model._name)])
-
-        # Filter fields based on the converter type
-        if converter == "relation-to-many":
-            vals_list = [f for f in vals_list if f.ttype == "many2many"]
-        elif converter == "field":
-            vals_list = [f for f in vals_list if f.ttype != "many2many"]
-        else:
-            vals_list = []
-        return [
-            {
-                "field_name": f.field_description,
-                "field_technical_name": f.name,
-                "field_type": f.ttype,
-                "field_comodel_name": f.relation,
-            }
-            for f in vals_list
-        ]
-
-    def action_cancel(self):
-        # custom cancel, unlinks the fields, the wizard itself
-        # and close window
-        self.unlink()
-        return {"type": "ir.actions.act_window_close"}
-
-    def action_save(self):
-        selected_count = 0
-        selected_field = False
-        for f in self.suggested_fields:
-            if f.selected:
-                selected_count += 1
-                selected_field = f
-
-        if selected_count > 1:
-            raise exceptions.UserError(
-                "You cannot select more than one field to build the expression"
-            )
-
-        elif selected_count == 0:
-            raise exceptions.UserError(
-                "You have to select one field to build the expression"
-            )
-        elif selected_field.field_type in ["many2one", "one2many"]:
-            # in this case we do not close the window.
-            # instead we refresh the wizard by showing the
-            # fields 1 field deeper
-            # and we update the expression field
-            if self.expression or self.expression != "":
-                self.expression += "." + selected_field.field_technical_name
-            else:
-                self.expression = selected_field.field_technical_name
-
-            # get comodel
-            comodel = self.env.get(selected_field.field_comodel_name)
-            if comodel is None:
-                return
-            vals_list = self.get_fields(comodel, self.substitution_id.converter)
-            for val in vals_list:
-                val["wizard_id"] = self.id
-
-            # remove previous fields
-            self.suggested_fields.unlink()
-            # add and create the next fields
-            fields_list = self.env["expression.builder.field"].create(vals_list)
-            self.suggested_fields = [(6, 0, fields_list.ids)]
-            # stay on updated wizard
-            return {
-                "type": "ir.actions.act_window",
-                "res_model": "expression.builder.wizard",
-                "view_mode": "form",
-                "res_id": self.id,
-                "target": "new",
-            }
-        # if the selected field is not relationnal:
-        if self.expression or self.expression != "":
-            # expression has already a value
-            self.substitution_id.write(
-                {
-                    "value": self.expression
-                    + "."
-                    + selected_field.field_technical_name,
-                }
-            )
-        else:
-            # expression is empty
-            self.substitution_id.write(
-                {
-                    "value": selected_field.field_technical_name,
-                }
-            )
-        # at the end, we unlink all of the temp data
-        # and close the window
-        return self.action_cancel()
diff --git a/wizard/expression_builder_field.py b/wizard/expression_builder_field.py
deleted file mode 100644
index c017b4fda42e9125d699bd8002459b78b0c8b1ad_d2l6YXJkL2V4cHJlc3Npb25fYnVpbGRlcl9maWVsZC5weQ==..0000000000000000000000000000000000000000
--- a/wizard/expression_builder_field.py
+++ /dev/null
@@ -1,39 +0,0 @@
-from odoo import fields, models
-
-
-class ExpressionBuilderField(models.TransientModel):
-    _name = "expression.builder.field"
-    _description = "Expression Builder Field"
-
-    wizard_id = fields.Many2one(
-        string="Expression builder",
-        comodel_name="expression.builder.wizard",
-        required=True,
-        ondelete="cascade",
-    )
-
-    field_name = fields.Char(
-        string="Field name",
-        help="The field's comprehensible name",
-    )
-
-    field_type = fields.Char(
-        string="Field Type",
-        help="The field's type (boolean, text, ...)",
-    )
-
-    field_comodel_name = fields.Char(
-        string="Comodel Name",
-        help="If the field is relational, store the comodel name here",
-    )
-
-    field_technical_name = fields.Char(
-        string="Field Technical Name",
-        help="The field's technical name",
-    )
-
-    selected = fields.Boolean(
-        string="Selected",
-        help="When selected, this field will be added to the substitution value",
-        readonly=False,
-    )
diff --git a/wizard/expression_builder_view.xml b/wizard/expression_builder_view.xml
deleted file mode 100644
index c017b4fda42e9125d699bd8002459b78b0c8b1ad_d2l6YXJkL2V4cHJlc3Npb25fYnVpbGRlcl92aWV3LnhtbA==..0000000000000000000000000000000000000000
--- a/wizard/expression_builder_view.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<odoo>
-    <record id="view_expression_builder_wizard_form" model="ir.ui.view">
-        <field name="name">expression.builder.wizard.form</field>
-        <field name="model">expression.builder.wizard</field>
-        <field name="arch" type="xml">
-            <form string="Build Expression">
-                <sheet>
-                    <field name="substitution_id" invisible="1" />
-                    <field name="suggested_fields" nolabel="1" colspan="2">
-                        <list
-                            no_open="true"
-                            editable="top"
-                            create="false"
-                            delete="false"
-                            default_order="field_name asc"
-                        >
-                            <field name="selected" />
-                            <field name="field_name" readonly="1" />
-                            <field name="field_technical_name" readonly="1" />
-                            <field name="field_type" readonly="1" />
-                            <field name="field_comodel_name" readonly="1" />
-                        </list>
-                    </field>
-                    <footer>
-                        <button
-                            string="Save"
-                            type="object"
-                            name="action_save"
-                            class="btn-primary"
-                        />
-                        <button
-                            string="Cancel"
-                            type="object"
-                            name="action_cancel"
-                            class="btn-secondary"
-                        />
-                    </footer>
-                </sheet>
-            </form>
-        </field>
-    </record>
-</odoo>