HMTL FORMS

COMP 126: Practical Web Design & Development for Everyone

the <form> element

<form method="POST" action="SOME_TARGET_URL">
  ...
</form>

<form> is a container for all the input-gathering elements inside it

 

the most common attributes of <form> are:

  • action: tells the form where to send the data
  • method: GET (user is requesting information) or POST (user is sending information; more secure & more common)

fields

<form method="GET" action="https://www.google.com/search">
  <input type="text" name="search-query">
</form>

Users need somewhere to enter the information they want to submit or request. We call these "fields". Each field should have its own unique "name" attribute and a type.

 

The most commonly used field types are

  • input: limited field for a certain kind of information
  • textarea: general text input area
  • select: for a checkbox or radio button

LABELS

<form method="POST" action="/">
  <label>
	username
  <input type="text" name="userid">
  </label>
</form>

Labels tell users what information should go in each field. You can nest fields inside a label element to link the label with the field.

Or you can keep the label and input elements separate and link them with matching for and id attributes.

<form method="POST" action="/">
  <label for="username">username</label>
  <input id="username" type="text" name="userid">
</form>

BUTTONS

<form method="POST" action="/">
  <label>
	username
  <input type="text" name="userid">
  </label>
  <button type="submit">submit</button>
</form>

The <button> element is used to submit a form. Its type value is SUBMIT.

TEXT FIELD <input> types

  • Phone number: <input type="tel" name="phone">
  • Email address: <input type="email" name="email-address">
  • Numbers: <input type="number" name="age">
  • URL: <input type="url" name="website">
  • And there are many more input types

FIELDSETS

Used to group related fields; require a legend element

<fieldset>
  <legend>Mother</legend>
  <label for="mother-given">Given Name</label>
  <input type="text" name="mother-given" id="mother-given">
  <label for="mother-family">Family Name</label>
  <input type="text" name="mother-family" id="mother-family">
</fieldset>
<fieldset>
  <legend>Father</legend>
  <label for="father-given">Given Name</label>
  <input type="text" name="father-given" id="father-given">
  <label for="father-family">Family Name</label>
  <input type="text" name="father-family" id="father-family">
</fieldset>

checkboxes (examples)

Allow users to choose more than one option

<label>
  <input type="checkbox" name="signup" value="yes">
  Would you like to receive discounts by email?
</label>

Selections from a group

<fieldset>
  <legend>What languages do you speak?</legend>
  <label>
    <input type="checkbox" name="language" value="ar">
    Arabic
  </label>
  <label>
    <input type="checkbox" name="language" value="es">
    Spanish
  </label>
  <label>
    <input type="checkbox" name="language" value="en">
    English
  </label>
</fieldset>

RADIO buttons (example)

For a single selection from a group

<fieldset>
  <legend>What is your preferred language?</legend>
  <label>
    <input type="radio" name="language" value="ar">
    Arabic
  </label>
  <label>
    <input type="radio" name="language" value="es">
    Spanish
  </label>
  <label>
    <input type="radio" name="language" value="en">
    English
  </label>
</fieldset>

Connecting an html form to a google sheet

A no-server way to collect form data!

what we're building

  • A standard HTML form...

  • ...with a small amount of JavaScript (you don't have to write it) to capture the form data.

  • Instead of a complex back-end server, we'll use a Google Sheet as our database...

  • ...resulting in a live contact form that drops submissions directly into a spreadsheet...

  • ...a form that you will then style with CSS.

HOW it works

  • The front end (HTML/CSS/JS)

    • When the user fills out your form in their browser, JavaScript intercepts the "submit" click

  • The connection (the Internet)

    • The JavaScript sends the form data to a unique URL leading to a Google Sheet

  • The back end (Google Apps Script & Sheets)

    • A script living in a Google Sheet "catches" the data

    • The script adds the data as a new row in the spreadsheet

1. COPY THIS form code into an html document

<div class="container">
    <form id="contact-form">
      <h3>get in touch!</h3>

      <label for="name">Name:</label>
      <input type="text" id="name" name="name" required />

      <label for="email">Email:</label>
      <input type="email" id="email" name="email" required />

      <label for="message">Message:</label>
      <textarea id="message" name="message" rows="4" required></textarea>

      <button type="submit">Submit</button>
      <p id="form-message"></p>
    </form>
</div>

2. The "Database" (google sheet)

  • Log into Google and create a new Google Sheet

  • Add column headers in the first row

    • These headers MUST exactly match the name attribute of your form inputs

    • You can choose your own headers (but they should not start with numbers or contain spaces!) depending on the needs of your form, as long as they're consistent with the associated name attributes of your form inputs

    • However, for this exercise, please use the headers timestamp, name, email, message

3. The "back end"

  • In your Google Sheet, go to Extensions > Apps Script; a new editor tab will open

  • Rename the project from "Untitled project" to something meaningful, like "Contact Form Handler"

  • Delete the default code inside the Code.gs file

4. Paste this into apps script

This script will act like a mini-server. The doPost function will run whenever data is sent to its URL (which you'll get in a moment)

function doPost(e) {
  try {
    var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
    var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];
    var newRow = headers.map(function(header) {
      return header.toLowerCase() === "timestamp" ? new Date() : e.parameter[header];
    });
    
    sheet.appendRow(newRow);
    
    return ContentService
      .createTextOutput(JSON.stringify({ "result": "success" }))
      .setMimeType(ContentService.MimeType.JSON);
  } catch (error) {
    return ContentService
      .createTextOutput(JSON.stringify({ "result": "error", "error": error.message }))
      .setMimeType(ContentService.MimeType.JSON);
  }
}

5. makE the script live

This step creates the public URL leading to the Google Sheet that your form will send data to.

  1. Click the blue Deploy button and select New deployment

  2. Click the gear icon and select Web app

  3. Fill in the settings:

    • Description: Contact Form Processor

    • Execute as: your username

    • Who has access: Anyone <--- CRITICAL STEP!

  4. Click Deploy

6. GET YOUR APP URL

  • Google will prompt you to Authorize access

  • Choose your Google account. You may see a "Google hasn't verified this app" warning. Click Advanced, then Go to [your project name] (unsafe); click Allow

  • Success! A dialog box will appear with your Web App URL

  • COPY THIS URL. You will need it for your JavaScript 

7. Back to the front end

  • Take a look at the HTML form code you copied at the beginning of this exercise

  • Note a couple of things:

    • The <form> tag has an id--in this case, id="contact-form"

    • Each <input> and <textarea> has a name attribute that matches a header in your Google sheet

8. add Javascript to the front end

Place this <script> block just before your closing </body> tag:

<script>
  const form = document.getElementById('contact-form');
  const formMessage = document.getElementById('form-message');
  const scriptURL = 'PASTE_YOUR_WEB_APP_URL_HERE';

  form.addEventListener('submit', e => {
    e.preventDefault();
    formMessage.textContent = 'Sending...';

    fetch(scriptURL, { method: 'POST', body: new FormData(form)})
      .then(response => {
        formMessage.textContent = 'Message sent successfully!';
        form.reset();
        setTimeout(() => { formMessage.textContent = ''; }, 5000);
      })
      .catch(error => {
        formMessage.textContent = 'Oops! Something went wrong.';
        console.error('Error!', error.message);
      });
  });
</script>

9. add your web app url to your script block

As the value of

const scriptURL='PASTE_YOUR_WEB_APP_URL_HERE';

<script>
  const form = document.getElementById('contact-form');
  const formMessage = document.getElementById('form-message');
  const scriptURL = 'PASTE_YOUR_WEB_APP_URL_HERE';

  form.addEventListener('submit', e => {
    e.preventDefault();
    formMessage.textContent = 'Sending...';

    fetch(scriptURL, { method: 'POST', body: new FormData(form)})
      .then(response => {
        formMessage.textContent = 'Message sent successfully!';
        form.reset();
        setTimeout(() => { formMessage.textContent = ''; }, 5000);
      })
      .catch(error => {
        formMessage.textContent = 'Oops! Something went wrong.';
        console.error('Error!', error.message);
      });
  });
</script>

10. a few notes about the js

  • const form = ...

    • Selects our form from the DOM.

  • const scriptURL = '...'

    • This is where you paste the URL you copied earlier!

  • form.addEventListener('submit', ...)

    • Tells the browser to listen for the form's submit event.

  • e.preventDefault();

    • The most important line! It stops the browser from reloading the page, so our script can run instead.

  • fetch(scriptURL, ...)

    • Sends the collected form data (new FormData(form)) to our Google Script URL using the POST method.

  • .then(...) and .catch(...)

    • Handles the response from Google. We show a success or error message to the user.

11. troubleshooting

  • Do your Google Sheet headers and name attributes match?

    • Do the column headers in your Google Sheet exactly match the name attributes in your HTML form? They are case sensitive (e.g., email vs Email)

  • Is the script deployed correctly?

    • Is the "Who has access" setting for your web app set to Anyone?

  • Is the URL correct?

    • Did you copy the full web app URL and paste it correctly into the scriptURL variable in your JavaScript?

12. AND now...

  • Test! Fill out your form and watch the submission appear instantly in your Google Sheet

  • Customize! Add more fields to your form (and sheet!). Try adding phone number, subject, etc.

  • Style! Now on to the in-class exercise

STyLING An HTML FORM

Notes on FORM DESIGN

  • required fields first, optional fields last

  • single-column layout is best for forms: better for usability and responsiveness

  • in most cases, and definitely on mobile labels should go ABOVE their fields to cut down on width

  • on desktop, labels can go to the left if it works

  • labels should be clear, concise, skimmable

selecting form elements

We frequently select form elements for styling by element name or attribute. (You can still use classes and IDs if you prefer, though.)

 

Selecting the form element name

Form elements can be selected by referring to their element names:

  • input: selects all the input fields
  • textarea: selects all the text areas
  • label: selects all level elements

 

Selecting the form element attribute

  • Form elements can also be selected by referring to their attributes using element attribute selectors:

  • input[type=text]: selects all input fields having type attribute set to text
  • input[type=password]: selects all input fields having type attribute set to password
  • input[type=number]: selects all input fields having type attribute set to number

selecting form elements: EXAMPLES

input[type=text] {
  width: 100%;
  padding: 12px;
  margin: 10px 0;
  box-sizing: border-box;
}

 input[type=button], input[type=submit], input[type=reset] {
  background-color: #04AA6D;
  border: none;
  color: white;
  padding: 16px 32px;
  text-decoration: none;
  margin: 4px 2px;
  cursor: pointer;
}

input,
textarea {
  border: none;
  padding: 0 10px;
  margin: 0;
  width: 80%;
  background: none;
}

126-forms

By tkjn

126-forms

  • 4,026