FABLED.DAY

contents

Discord Webhook Forms for Static Sites

This page actually has two forms that I’ve been playing with. Both have the same Javascript-ery for the most part, and quite nearly the same HTML as well. Still, choose one below to jump to that particular section of the article:

  1. One has a lavish stylesheet affording as much aesthetic as I could manage.
  2. The other is a stripped-down version with a minimalist stylesheet.

The first would be useful for creating a full-page (or just very large) form, and it has a vintage theme.The second is basically tapered for easy insertion into an existing page in order to conform to your default stylesheet. I tried to annotate both to make them easy to customize, either way.

You can view both versions of this form with all three components (CSS, HTML, Javascript) together on Codepen, as well as see a live preview that you can edit on the fly...

We all really do need a contact form on our website. True, we could just toss our email address up there, but that’s a bit of a hassle for visitors who might just want to type in a quick question. I prefer to post a contact form for short inquiries, a guestbook/askbox for public questions, and my email for longer inquiries.

There’s a lot of different options for contact forms. A lot of third-party sites offer solutions for this. Initially, on my other site, I used one of those, but it was just ridiculous, had advertisements, and was messy, not easy to customize. I hunted until I discovered how to send messages from my website to a Discord server of my own creation, where I can easily get alerts about them. Naturally, this works amazingly for me and others like me who constantly have Discord running in the background of their devices.

The Discord webhook forms you see below are based on the work of Goblin-Heart, also known as Sadgrl on neocities. You can find her version of the code here. I didn’t find anything on her site about not doing any heavy modifications and resharing it, so I’ve done that. If I’m in error and Goblin-Heart disapproves, she is welcome to contact me and I’ll be respectful of her wishes immediately.

My version features a litmus test (of a rudimentary sort) to ensure both that all portions of the form are filled out, and that the email address that the user types in actually matches the proper format. While this is far from an actual CAPTCHA, it will likely cut down on the possibility of some person or bot just typing gibberish in your form. I understand that CAPTCHAs are extremely useful and a lot of people do worry about shoving a webhook out there like this, but honestly? My other site has had 80K visits (according to neocities itself, though many were probably not genuine visitors) since last November, and hasn’t had any Discord spam. If I learn to set up a CAPTCHA (unlikely), I'll share it!

It also, rather than using an alert popup message, will simply erase the form upon receipt of the message. It then displays a message (customizable) thanking the visitor in place of the form. It also includes an element just below the form which will become visible if the form contents do not match the stipulations mentioned before (ie, all fields and email syntax). This part just hisses at the visitor and lets them know what they ought to do next.

The Discord message itself is also formatted slightly differently, with the date removed (given that timestamps are native to Discord) and the addition of a title to each (“NEW SITE MESSAGE”). There’s some bolding of the text in order to make things more legible within the app, too. You can play with this if you look into Discord’s markdown system a bit.

Creating Discord Webhooks

You don’t need Discord Nitro to make these, and no, don’t ask me what a webhook even is. At least, don’t ask me to explain it in my own words. I assume it’s simply a term for something that connects the app to the web. I don’t particularly care at this juncture. Sorry. If you feel like explaining it to me, feel free, but please don’t be rude - we all start somewhere. I’m learning more day by day.

Either way, Discord webhooks are easy to create. Wondering how to create a webhook? I suggest reading Discord’s tutorial - you don’t have to read much, just how to make one, and snag the URL. That (initially, at least) seems to cover it for getting this to work.

I recommend creating a new server to make the webhook, all your own, just for your site. Perhaps add other collaborators, if there are any, or otherwise, keep it to yourself. All of the messages sent by the web form will appear in the server in a channel you create. You’ll want it private for that reason, unless you want other people (in the server) seeing them.

So, create a channel (presumably just) for the web form (It doesn’t matter what you call it), and create a webhook for that channel. The URL of the webhook can then be copied and inserted into the Javascript snippets that I’ll provide later in this article.

First Version

You can find this version of the form, and all components, on Codepen here.

The fancified version is kind of snazzy, and works well for a full-page usage. It features a form with rounded corners and shadows meant to resemble old paper, and other interesting colors and features.

All the colors and such in this can be customized in the CSS, of course. If you, for example, want a patterned background (as a gif or jpeg), feel free to just add it, and the shadows will overlay it, creating (often, with some patterns) a nice papery effects. If you want the “paper” to be a slightly different shade, or the buttons, shadowing, etc - feel free. I tried to annotate the CSS to make this easier.

CSS

The only CSS that is really exclusive to the form’s functionality is #send applied to the button itself, the inclusion of an empty element called #hiss for warning messages, and wrapping the form in an element called #inquiry. You also have to include an empty element after #inquiry called #sent, to display a message of thanks when the inquiry is received by Discord properly. This is done in the HTML, and doesn’t require CSS to make it work, per se. Still, it affords us many customization options.

Unlike the plain version, this version of the form uses a class called .letter to engulf the entire form in a rounded paper-like backdrop, without any images. It’s all done with drop-shadows, and while it doesn’t look perfect, it’s somewhat cute. It’s a decent start, in my opinion, and, with the use of graphics and other features, you can do much more.

    
    /* Below styles the rounded, shadowy container that holds the entire thing */
    .letter {
      text-align: center;
      font-size: 1.2rem;
      color: #4f261c;
      background-color: #ede0d4;
      box-shadow: 0 0 10px rgba(0, 0, 0, 0.9), 0px 0px 500px 20px #917d66 inset;
      margin: 2rem auto 2rem;
      width: 40%;
      border-radius: 1rem;
      padding: 2rem;
      padding-bottom: 7rem;
      position: relative;
    }
    /* below styles the title of the form */
    .letter h1 {
      font-size: 4rem;
    
      text-transform: uppercase;
      font-style: italic;
      letter-spacing: 0.5rem;
      color: #9e5e6f;
      font-family: impact;
      text-shadow: 1px 1px 3px #f4e9df;
    }
    
    /* below styles form elements, ie, the buttons and fields */
    textarea,
    input,
    button {
      line-height: 1.6rem;
      font-size: 1.6rem;
      width: 80%;
      display: block;
      margin: auto;
      border: 1px dashed #9e5e6f;
      margin-top: 0.5rem;
      outline: none;
      font-family: inherit;
      appearance: none;
    }
    textarea,
    input {
      color: #4f261c;
      padding: 0.4rem;
      background-color: transparent;
    }
    textarea {
      height: 10rem;
      resize: none;
    }
    
    button {
      border-radius: 0.25rem;
      background-color: #9e5e6f;
      color: #e5cab0;
      margin-top: 1.5rem;
      width: 40%;
      padding: 0.6rem;
      box-shadow: 1px 1px 5px #f4e9df;
      font-size: 1.5rem;
      transition: background-color 0.2s;
      &:hover,
      :focus {
        outline: none;
        color: #4f261c;
        background-color: #dc7f8e;
      }
    }
    input[type="text"]:focus,
    input[type="email"]:focus,
    textarea:focus {
      outline: none;
    }
    
    input::placeholder,
    textarea::placeholder {
      color: #4f261c;
    }
    /* below styles the polite thanks that the visitor receives when the message is sent */
    #sent {
      font-size: 1.6rem;
      margin: 2rem;
    }
    
    /* below styles messages asking the visitor to properly fill out all fields */
    #hiss {
      color: #8b0000;
      font-size: 1.5rem;
      margin: 1.4rem;
    }
    
    /* below provides some measure of accommodation for smaller screens by stripping formatting */
    @media screen and (max-width: 600px) {
      .letter {
        background: none;
        width: 70%;
        padding: 1em;
        box-shadow: none;
        margin: 0 auto 0;
        position: relative;
      }
    }
    
    .sent {
      font-size: 2.3rem;
      margin: 1rem;
    }
    

HTML

Here’s the HTML for the form. It ought to be inserted into the page where you’d like to shove the contact form. It can go on a page by itself provided you set up the header, body tags, etc properly. You could also integrate it with your site underneath a header or something if you change the CSS up a bit, but I don’t recommend putting it on a sidebar or other small space without some serious modifications. You can, of course, change all the text within it that begins with the words “Enter your...”

<!-- beginning the container of the entire form -->
    <div class="letter">
        <!-- your form title below, of course -->
        <h1>Contact Me</h1><!-- the #inquiry element containing the questions themselves starts next -->
        <div id="inquiry">
          <input type="text" id="name" placeholder="Give your name or an interesting alias..."><br>
          <input type="email" id="email" placeholder="Enter your email address..."><br>
          <textarea id="question" placeholder="Type your comments or inquiries here..."></textarea>
          <button id="send">Send</button>
          <!-- below is an empty element #hiss; if the form is submitted incorrectly, the javascript will fill it with a message to the visitor, a hiss of sorts that you can customize in the javascript -->
          <div id="hiss"></div>
        </div><!-- the form container (#inquiry) element ends here -->
      
        <!-- below is another empty element #sent; once the form has been properly submitted and the javascript has removed the form itself from view; this one will be filled with a polite thank you message customizable in the javascript.  -->
        <div id="sent"></div>
      </div><!-- end of the main form container -->

Javascript

The fields containing the words “darling,” “dearest” etc are all messages to the visitor, which can be changed.

The usual rules about the contents of Javascript HTML applies here, though. Please add a \ just before any quotation marks, double or single, when writing for these fields. You can use this weak little converter I made to (attempt) to do this automatically, as well as removing line breaks.

Be absolutely sure that you replace the line indicated (where it says “INSERT THE DISCORD WEBHOOK URL HERE OR ALL IS LOST”) with your Discord webhook URL, or the form will be completely useless.

document.getElementById("send").onclick = function () {
      const nameInput = document.getElementById("name");
      const emailInput = document.getElementById("email");
      const questionInput = document.getElementById("question");
    
      // THIS NEXT PART REMOVES WHITESPACE BEFORE AND AFTER THE USER'S INPUT, BUT DOESN'T MESS WITH IT OTHERWISE. THIS MAKES IT SO THAT USERS CAN'T JUST LEAVE THEM BLANK.
    
      let name = nameInput.value.trim();
      let email = emailInput.value.trim();
      let question = questionInput.value.trim();
    
      // WE'RE GOING TO CHECK TO MAKE SURE THAT THE USER FILLS OUT ALL THE FIELDS. IF NOT, THE FORM WILL HISS AT THEM AND JUST SIT THERE.
      if (!name || !email || !question) {
        const messageElement = document.getElementById("hiss");
        messageElement.innerHTML = "Psst...fill out all fields, dearest!";
        return;
      }
    
      // WE'RE GOING TO NOW MAKE SURE THAT THE USER HAS FILLED IN AT LEAST A VALID-LOOKING EMAIL ADDRESS USING THE NORMAL PATTERN ONE TYPICALLY SEES FOR SUCH. IF NOT, THE FORM HISSES AND GLARES. I GOT THIS PATTERN THINGY FROM ANOTHER SITE TUTORIAL BUT IT DOES SEEM TO WORK HERE TOO.
    
      const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
      if (!emailPattern.test(email)) {
        document.getElementById("email").style.border = "3px dashed #8b0000";
        const messageElement = document.getElementById("hiss");
        messageElement.innerHTML =
          "Psst. That is not a valid email address, darling!";
        return;
      }
    
      // YOU MUST INSERT YOUR DISCORD WEBHOOK URL BELOW OR THIS ENTIRE FORM WILL BE UTTERLY POINTLESS AND NON-FUNCTIONAL.
      const request = new XMLHttpRequest();
      request.open("POST", "INSERT DISCORD WEBHOOK URL HERE OR ALL IS LOST");
      request.setRequestHeader("Content-type", "application/json");
    
      // HERE, WE PREP WHAT WE RECEIVE FROM THE USER TO BE SENT TO DISCORD.
    
      const formData = {
        "Name: ": name + "\n",
        "Email: ": email + "\n",
        "Question: ": question
      };
    
      // HERE, THE MESSAGE IS FORMATTED FOR DISCORD. NOTE THE MARKDOWN TAGS FOR DISCORD, WHICH ADD BOLD AND ITALIC TEXT FOR EMPHASIS TO THE TITLE "NEW SITE MESSAGE" AND THE FORM FIELD TITLES.
    
      const msg =
        "***NEW SITE MESSAGE*** " +
        "\n" +
        "**Name:** " +
        formData["Name: "] +
        "**Email:** " +
        formData["Email: "] +
        "**Question:** " +
        formData["Question: "];
    
      // THE USERNAME OF ALL MESSAGES WILL DEFAULT TO "SITE INQUIRY" UNLESS CHANGED BELOW.
    
      const params = {
        username: "Site Inquiry",
        content: msg
      };
    
      request.send(JSON.stringify(params));
    
      // POLITELY INFORMS THE USER THAT THE MESSAGE HAS BEEN RECEIVED BY FILLING THE ELEMENT #SENT WITH THE HTML BELOW IN THE QUOTATION MARKS
      const messageElement = document.getElementById("sent");
      messageElement.innerHTML =
        "Your message has been sent, darling. I will reply as soon as possible! If you were rude, you will regret it.";
    
      // HERE, THE FORM ITSELF IS HIDDEN FOLLOWING SUBMISSION
      document.getElementById("inquiry").style.display = "none";
    };
    
      

Second Version

You can find this version of the form, and all components, on Codepen here.

This is the second version of the form, which features hardly any CSS styling. This allows you to fill in your own and for your site’s existing theme to apply to the form fields and such. The version you see below would be ideal to add to a sidebar (provided it’s big enough already), as you can see on this very page, to the left.

CSS

As noted above, there isn’t CSS for this, really, except for a bit that assures the form itself functions properly and nothing overlaps, no elements crash into each other and explode, etc… you may, of course, customize much further. The below list includes everything specific to the form.

/* I'm including as little CSS here as possible since this version of the form is meant to be as stripped-down as possible and easily insertable into existing themes.  */

/* below styles form elements, ie, the buttons and fields */
textarea,
input,
button {
  margin: 0.1rem;
  color: #000;
}

input::placeholder,
textarea::placeholder {
  color: #000;
}
/* below styles the polite thanks that the visitor receives when the message is sent */
#sent {
  font-size: 1.6rem;
}

/* below styles messages asking the visitor to properly fill out all fields */
#hiss {
  color: #8b0000;
  font-size: 0.9rem;
}

HTML

This HTML contains all the essential bits of the full version. I removed the title, and it lacks the .letter class that envelopes the entire form; add your own versions of those if necessary.


<!-- the #inquiry element containing the questions themselves starts next -->
<div id="form">
  <input type="text" id="name" placeholder="Give your name or an interesting alias..."><br>
  <input type="email" id="email" placeholder="Enter your email address..."><br>
  <textarea id="question" placeholder="Type your comments or inquiries here..."></textarea><br>
  <button id="send">Send</button>
  <!-- below is an empty element #hiss; if the form is submitted incorrectly, the javascript will fill it with a message to the visitor, a hiss of sorts that you can customize in the javascript -->
  <div id="hiss"></div>
</div><!-- the form container (#inquiry) element ends here -->

<!-- below is another empty element #sent; once the form has been properly submitted and the javascript has removed the form itself from view; this one will be filled with a polite thank you message customizable in the javascript.  -->
<div id="sent"></div>

Javascript

This is, essentially, the same as the previous one. I’m basically copying from the earlier part of this page for that reason, just in case you skipped it. The fields containing the words “darling,” “dearest” etc are all messages to the visitor, which can be changed.

The usual rules about the contents of Javascript HTML apply here, though. Please add a \ just before any quotation marks, double or single, when writing for these fields. You can use this weak little converter I made to (attempt) to do this automatically, as well as removing line breaks.

Be absolutely sure that you replace the line indicated with your Discord webhook URL, or the form will be completely useless.

document.getElementById("send").onclick = function () {
      const nameInput = document.getElementById("name");
      const emailInput = document.getElementById("email");
      const questionInput = document.getElementById("question");
    
      // THIS NEXT PART REMOVES WHITESPACE BEFORE AND AFTER THE USER'S INPUT, BUT DOESN'T MESS WITH IT OTHERWISE. THIS MAKES IT SO THAT USERS CAN'T JUST LEAVE THEM BLANK.
    
      let name = nameInput.value.trim();
      let email = emailInput.value.trim();
      let question = questionInput.value.trim();
    
      // WE'RE GOING TO CHECK TO MAKE SURE THAT THE USER FILLS OUT ALL THE FIELDS. IF NOT, THE FORM WILL HISS AT THEM AND JUST SIT THERE.
      if (!name || !email || !question) {
        const messageElement = document.getElementById("hiss");
        messageElement.innerHTML = "Psst...fill out all fields, dearest!";
        return;
      }
    
      // WE'RE GOING TO NOW MAKE SURE THAT THE USER HAS FILLED IN AT LEAST A VALID-LOOKING EMAIL ADDRESS USING THE NORMAL PATTERN ONE TYPICALLY SEES FOR SUCH. IF NOT, THE FORM HISSES AND GLARES. I GOT THIS PATTERN THINGY FROM ANOTHER SITE TUTORIAL BUT IT DOES SEEM TO WORK HERE TOO.
    
      const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
      if (!emailPattern.test(email)) {
        document.getElementById("email").style.border = "3px dashed #8b0000";
        const messageElement = document.getElementById("hiss");
        messageElement.innerHTML =
          "Psst. That is not a valid email address, darling!";
        return;
      }
    
      // YOU MUST INSERT YOUR DISCORD WEBHOOK URL BELOW OR THIS ENTIRE FORM WILL BE UTTERLY POINTLESS AND NON-FUNCTIONAL.
      const request = new XMLHttpRequest();
      request.open("POST", "INSERT DISCORD WEBHOOK URL HERE OR ALL IS LOST");
      request.setRequestHeader("Content-type", "application/json");
    
      // HERE, WE PREP WHAT WE RECEIVE FROM THE USER TO BE SENT TO DISCORD.
    
      const formData = {
        "Name: ": name + "\n",
        "Email: ": email + "\n",
        "Question: ": question
      };
    
      // HERE, THE MESSAGE IS FORMATTED FOR DISCORD. NOTE THE MARKDOWN TAGS FOR DISCORD, WHICH ADD BOLD AND ITALIC TEXT FOR EMPHASIS TO THE TITLE "NEW SITE MESSAGE" AND THE FORM FIELD TITLES.
    
      const msg =
        "***NEW SITE MESSAGE*** " +
        "\n" +
        "**Name:** " +
        formData["Name: "] +
        "**Email:** " +
        formData["Email: "] +
        "**Question:** " +
        formData["Question: "];
    
      // THE USERNAME OF ALL MESSAGES WILL DEFAULT TO "SITE INQUIRY" UNLESS CHANGED BELOW.
    
      const params = {
        username: "Site Inquiry",
        content: msg
      };
    
      request.send(JSON.stringify(params));
    
      // POLITELY INFORMS THE USER THAT THE MESSAGE HAS BEEN RECEIVED BY FILLING THE ELEMENT #SENT WITH THE HTML BELOW IN THE QUOTATION MARKS
      const messageElement = document.getElementById("sent");
      messageElement.innerHTML =
        "Your message has been sent, darling. I will reply as soon as possible! If you were rude, you will regret it.";
    
      // HERE, THE FORM ITSELF IS HIDDEN FOLLOWING SUBMISSION
      document.getElementById("inquiry").style.display = "none";
    };
    
    
top