Placeholder Forms

:discourse2: Summary Placeholder Forms will let you build dynamic documentation, by creating a form that replaces any occurrence of a =PATTERN= in your post with the value from a text or selectable input field.
:eyeglasses: Preview Preview on Discourse Theme Creator
:hammer_and_wrench: Repository Link
:open_book: New to Discourse Themes? Beginner’s guide to using Discourse Themes

Install this theme component


Add placeholders to posts in this format:

[wrap=placeholder key=NAME description="Your name"][/wrap]
[wrap=placeholder key=COUNTRY default=US defaults=FR,DE,US,CN,AU,CA][/wrap]

Your email:

And this will result in:

This is used in mailing list

Your email:

As seen above, text inside the wrapper will be used as a long description.

[wrap=placeholder key=NAME description="Your name"]
This is used in mailing list

Available keys

  • key: The key that should be replaced in your post
  • default/defaults: default value(s)
  • description: a placeholder text for the input


# create a new plugin
rails g plugin =PLUGIN_NAME=
cd plugins/=PLUGIN_NAME=

We use it to create runbooks, howtos and reusable templates (it will work in code blocks). Please share your use cases!


Translation Default
toolbar.builder Add Placeholder
builder.errors.no_key A key is required.
builder.title Add Placeholder
builder.insert Insert
builder.key.label Key
builder.key.description The =Key= to be replaced in the post.
builder.description.label Description
builder.description.description Description displayed on input with no value set.
builder.values.label Default value(s)
builder.values.description Optional value(s) for your placeholder, if multiple values are defined, a select will be used.

:discourse2: Hosted by us? Theme components are available to use on our Standard, Business, and Enterprise plans.

Last edited by @JammyDodger 2024-06-13T22:28:45Z

Check documentPerform check on document:

The big issue with math handling like this, is that you need to eval() and eval is unsafe, so you need to use some lib which provide a safe eval with a limited subset of the real eval. I’m unsure we want all this complexity for such a rare case.


I tried ! and that would be a neat composer-preview-redux-in-OP kind of thing but… :pensive: I must be missing something, if I understand correctly the Reply Template component takes the raw and looks for “replacers”, but the Placeholder Forms component decorates the cooked?

What I’m trying to do is ease my users into adding some quizz Q&As in a topic, with minimal technical friction, clicks or even key strokes, :heavy-sigh: :roll_eyes:

[wrap=placeholder key="question" description="question"][/wrap]
[wrap=placeholder key="réponse" description="réponse"][/wrap]

[wrap=template key="template-spoiler" action="reply" tagsList="#qui, #quand, #où, #comment"]

## Question
### Réponse
*Étiquette(s) ?*

which gives

so far so good, but unfortunately, the placeholders =question= and =réponse= are kept in the composer when hitting the template button

Yes I’m not sure what I was thinking when I wrote this… I probably had a different use case in mind, but can’t remember.

It can’t work this way for sure. I will think a little bit about this… Both theme components were experiments at the time and might deserve better treatment as people have been using it quite frequently.


Thank you !

happy lets go GIF by Shalita Grant


:grin: I don’t know what’s cookin’ in the chef kitchen, but as I usually stuff myself with pistachios or whatnot while waiting, I managed to make it work (for my specific use of course as I’ve almost no idea of what I’m doing, but hey… :sweat_smile: )


Ideally I would like to be able to let admin define their own replacers, but eval is risky (and not even possible with a secure csp) so I’m not sure how I could achieve this…


First of all - great and really helpful theme component.

But I think I found a bug. If I use a placeholder in a code snippet, that contains backticks (`), it is not working. An example is a SQL code snippet:

            id FROM (
                    id FROM `=TABLENAME=`
                ORDER BY
                    id DESC
                LIMIT 20
) subquery);

TABLENAME gets never replaced (if there is a TABLENAME placeholder).

Would be cool if this also included some Jinja2 like conditions. So that e.g. someone could create a key red and map that to the icon :red_circle:, orange would map to :orange_circle:. But I can do without of course, but would’ve been cool to have these test conditions.

I really love this component. :star_struck:

“And you really live by the =NOUN_1=? What a =ADJECTIVE_1= life!”

“By it and with it and on it and in it,” said =PERSON_1=. “It’s brother and sister to me, and aunts, and =NOUN_2=, and food and drink, and (=ADJECTIVE_2=) =VERBING_1=. It’s my =NOUN_3=, and I don’t want any other. What it hasn’t got is not worth =VERBING_2=, and what it doesn’t know is not worth =VERBING_3=. Lord! the =NOUNS_1= we’ve had together! Whether in winter or summer, spring or autumn, it’s always got its =NOUN_4= and its =NOUNS_2=. When the =NOUNS_3= are on in February, and my =NOUNS_4= and basement are brimming with =NOUN_5= that’s no good to me, and the =COLOR_1= =NOUN_6= runs by my best =NOUN_7= window; or again when it all drops =ADVERB_1= and shows patches of =NOUN_8= that smells like =FOOD_1=, and the =NOUNS_5= and =NOUNS_6= clog the channels, and I can =VERB_1= about =MOISTURE= =NOUN_9= over most of the =NOUN_10= of it and find fresh =FOOD_2= to eat, and things =ADJECTIVE_3= people have dropped out of =NOUNS_7=!”

Original taken from Standard Ebooks version of The Wind in the Willows, available to read online (search for By it and with it).


Hello :wave:

Thanks for this component :heart: It fits perfectly what I try to achieve now. Actually my first thought was it would be super cool if it can be combine with Reply Template component. But unfortunately it’s not possible as the posts above explained it. :confused:

I’ve found a workaround for this to use it as a template, it works with link to new topics and link to new personal messages.

Here is how made it:

1. Create a Placeholder form (to keep it simple I use the example in OP)

Your email:

2. Create a link to new topic:
I set up in the link:

  1. category
  2. title
  3. body

If you want to add empty lines, use \ so it won’t break the link or to make it invisible you can use   which will add a space in the new line. It will be a part of the template and makes empty line,

<a href=" is a topic created by =NAME=&body=Hello :wave:
This is a test topic... Let's see the placeholder form.
Your email:
">Use template as new topic</a>

3. Create a topic preview

Selected category


Topic title

This is a topic created by =NAME=

Topic body

Hello :wave:

This is a test topic… Let’s see the placeholder form.

Your email:

4. Create “Use template as new topic” button (in the example above this is a link you can make button from this)

Make a [wrap] element from this text. This makes it available to target it with CSS and style it. I add this to below.

<a href=" is a topic created by =NAME=&body=Hello :wave:
This is a test topic... Let's see the placeholder form.
Your email:
">[wrap=template-button]Use template as new topic[/wrap]</a>

Styling [wrap=template-button]
something like :arrow_down_small:

Common / CSS

[data-wrap="template-button"] {
  background: var(--tertiary);
  color: var(--secondary);
  border-radius: var(--d-button-border-radius);
  padding: 0.5em 0.65em;
  transition: background 0.25s;
  &:hover {
    background: var(--tertiary-hover);
    color: var(--secondary); 

The template button will looks like this :arrow_down_small:



Use template as new topic

I hope this little tutorial will help someone who needs something similar :slightly_smiling_face:

Edit: I’ve seted up a category chooser which add the ability to create topic in different categories.

Check the raw version of this post…


That’s amazing Don, thank you. This actually suits one of my needs very well :slight_smile:


Something to note is that code blocks sometimes cause problems:

usermod -aG sudo =USERNAME=

In this case, highlight.js assumes this is Java and converts the codeblock to:

<code class="hljs language-java" data-highlighted="yes">
  usermod -
  <span class="hljs-type">aG</span> 
  <span class="hljs-variable">sudo</span> 
  <span class="hljs-operator">=</span>

I’m able to fix it by signaling this is actually a shell command:

    usermod -aG sudo =USERNAME=

That results in:

usermod -aG sudo =USERNAME=

If all else fails, text prevents highlight.js from messing with the placeholders.

A more general solution (that Meta Discourse must be using) is to change the default code lang setting from auto to plaintext or somesuch. :wink:

Not that it matters much, but using java is a way to avoid having the placeholder expand when you want to write about placeholders.

1 Like

Can you check the preview link? It seems to be broken for me.

CleanShot 2024-06-05 at 16.34.16

1 Like

This is an amazing feature, and I can see many uses for it.
However, in our reply, is it possible to hide the =(name)= until the user starts typing in the text box? I feel that users (especially new ones) may not understand its purpose, or, it looks like incorrect formatting.

I think I’ve got one working again (:crossed_fingers: :slight_smile:)

I’ve also added it to so you can have more of a hands-on play with it. :+1:

1 Like

Perhaps you could enter a default value that will display instead.

1 Like

That worked! Thank you!