TypeScript: Building a Simple Web-Based Feedback Form

In today’s digital landscape, gathering user feedback is crucial for improving products, services, and overall user experience. Imagine you’re building a website or web application. How do you efficiently collect valuable insights from your users? While there are many third-party services, building a simple, customizable feedback form directly into your application offers greater control and flexibility. This tutorial will guide you through creating a web-based feedback form using TypeScript, a superset of JavaScript that adds static typing, which helps catch errors early and improves code maintainability.

Why TypeScript?

Before diving in, let’s briefly discuss why TypeScript is a great choice for this project. TypeScript provides:

  • Static Typing: TypeScript allows you to define the data types of your variables, function parameters, and return values. This helps catch type-related errors during development, leading to more robust and reliable code.
  • Improved Code Readability: Type annotations make your code easier to understand and maintain, especially in larger projects.
  • Enhanced Developer Experience: TypeScript offers excellent tooling support, including autocompletion, refactoring, and error checking in most IDEs.
  • Modern JavaScript Features: TypeScript supports the latest JavaScript features, allowing you to write cleaner and more efficient code.

Project Setup

Let’s set up our project. You’ll need Node.js and npm (Node Package Manager) installed on your system. Open your terminal or command prompt and follow these steps:

  1. Create a Project Directory: Create a new directory for your project and navigate into it.
mkdir feedback-form-typescript
cd feedback-form-typescript
  1. Initialize npm: Initialize a new npm project.
npm init -y
  1. Install TypeScript: Install TypeScript as a development dependency.
npm install --save-dev typescript
  1. Create a `tsconfig.json` file: This file configures the TypeScript compiler. Create it in your project root with the following content:
{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"]
}

This configuration specifies that we’ll compile TypeScript to ES5 JavaScript, use CommonJS modules, output the compiled files to a `dist` directory, and the source files are in `src` directory. The `strict` option enables strict type checking. `esModuleInterop` helps with importing modules, `skipLibCheck` skips type checking of declaration files, and `forceConsistentCasingInFileNames` enforces consistent casing in file names.

  1. Create Source Directories and Files: Create a `src` directory and, within it, create an `index.ts` file. This is where we’ll write our TypeScript code.
mkdir src
touch src/index.ts

Building the Feedback Form

Now, let’s build the feedback form. We’ll start with the basic HTML structure, then add TypeScript to handle form submissions and validation. We will keep it very simple for this tutorial, you can expand it with more complex features later.

1. HTML Structure (index.html)

Create an `index.html` file in your project root with the following HTML structure:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Feedback Form</title>
    <style>
        body {
            font-family: sans-serif;
            margin: 20px;
        }
        label {
            display: block;
            margin-bottom: 5px;
        }
        input, textarea {
            width: 100%;
            padding: 8px;
            margin-bottom: 10px;
            border: 1px solid #ccc;
            border-radius: 4px;
            box-sizing: border-box; /* Important for width */
        }
        button {
            background-color: #4CAF50;
            color: white;
            padding: 10px 15px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
        }
        .error {
            color: red;
            margin-bottom: 10px;
        }
    </style>
</head>
<body>
    <h2>Feedback Form</h2>
    <div id="feedback-form">
        <div id="error-message" class="error"></div>
        <label for="name">Name:</label>
        <input type="text" id="name" name="name">

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

        <label for="feedback">Feedback:</label>
        <textarea id="feedback" name="feedback" rows="4"></textarea>

        <button type="submit" id="submit-button">Submit</button>
    </div>
    <script src="dist/index.js"></script>
</body>
</html>

This HTML provides a basic form with fields for name, email, and feedback. It also includes a place to display error messages. The `<script src=”dist/index.js”></script>` tag links to our compiled JavaScript file.

2. TypeScript Code (src/index.ts)

Now, let’s write the TypeScript code to handle form submissions and validation. Open `src/index.ts` and add the following code:


// Define an interface for the feedback data
interface FeedbackData {
    name: string;
    email: string;
    feedback: string;
}

// Get references to the form elements
const form = document.getElementById('feedback-form') as HTMLDivElement | null;
const nameInput = document.getElementById('name') as HTMLInputElement | null;
const emailInput = document.getElementById('email') as HTMLInputElement | null;
const feedbackTextarea = document.getElementById('feedback') as HTMLTextAreaElement | null;
const submitButton = document.getElementById('submit-button') as HTMLButtonElement | null;
const errorMessage = document.getElementById('error-message') as HTMLDivElement | null;

// Function to validate email
const isValidEmail = (email: string): boolean => {
    const emailRegex = /^[w-.]+@([w-]+.)+[w-]{2,4}$/;
    return emailRegex.test(email);
};

// Function to display error messages
const displayError = (message: string) => {
    if (errorMessage) {
        errorMessage.textContent = message;
    }
};

// Function to clear error messages
const clearError = () => {
    if (errorMessage) {
        errorMessage.textContent = '';
    }
};

// Function to handle form submission
const handleSubmit = (event: Event) => {
    event.preventDefault(); // Prevent the default form submission behavior
    clearError(); // Clear any previous errors

    // Check if the elements are not null
    if (!nameInput || !emailInput || !feedbackTextarea || !form) {
        console.error('One or more form elements are null.');
        return;
    }

    // Get the values from the form inputs
    const name = nameInput.value;
    const email = emailInput.value;
    const feedback = feedbackTextarea.value;

    // Input validation
    if (!name.trim()) {
        displayError('Name is required.');
        return;
    }

    if (!email.trim()) {
        displayError('Email is required.');
        return;
    }

    if (!isValidEmail(email)) {
        displayError('Invalid email format.');
        return;
    }

    if (!feedback.trim()) {
        displayError('Feedback is required.');
        return;
    }

    // Create feedback data object
    const feedbackData: FeedbackData = {
        name,
        email,
        feedback,
    };

    // Simulate sending data (replace with your actual submission logic)
    console.log('Feedback submitted:', feedbackData);
    displayError('Thank you for your feedback!'); // Display a success message

    // Clear the form
    nameInput.value = '';
    emailInput.value = '';
    feedbackTextarea.value = '';
};

// Add an event listener to the submit button
if (submitButton) {
    submitButton.addEventListener('click', handleSubmit);
}

Let’s break down this code:

  • Interfaces: The `FeedbackData` interface defines the structure of our feedback data. This is an example of TypeScript’s type system in action, ensuring the data we work with has a predictable structure.
  • Element References: We get references to the form elements using `document.getElementById()`. The `as` keyword and type assertions (e.g., `as HTMLInputElement`) tell TypeScript the expected type of these elements. This allows for type checking and autocompletion.
  • Email Validation: The `isValidEmail` function uses a regular expression to validate the email format.
  • Error Handling: The `displayError` and `clearError` functions handle displaying and clearing error messages.
  • Form Submission Handling: The `handleSubmit` function is the core of our form logic. It:
    • Prevents the default form submission.
    • Clears any existing error messages.
    • Gets the values from the form inputs.
    • Validates the input data (name, email, feedback).
    • Creates a `feedbackData` object.
    • Simulates sending the data to a server (replace this with your actual submission logic). In this case, it logs the data to the console.
    • Displays a success message.
    • Clears the form fields.
  • Event Listener: We add an event listener to the submit button to call the `handleSubmit` function when the button is clicked.

3. Compile and Run

Now, compile your TypeScript code to JavaScript. In your terminal, run:

tsc

This command uses the TypeScript compiler (`tsc`) to compile the `index.ts` file into `index.js` in the `dist` directory. Open `index.html` in your web browser. You should see the feedback form. When you fill out the form and click the submit button, the form data will be logged to your browser’s console (press F12 to open the developer tools and view the console).

Adding More Features

This is a basic example, and you can extend it with several more features:

  • Server-Side Integration: Instead of logging the data to the console, you’ll likely want to send the data to a server. You can use the `fetch` API or a library like Axios to send a POST request to a server-side endpoint. This endpoint would then handle saving the feedback to a database or processing it in some other way.
  • More Input Validation: Add more validation rules, such as checking the length of the feedback, validating the name format, or checking for profanity.
  • Real-time Feedback: Provide real-time feedback to the user as they type, such as highlighting invalid email formats or displaying a character count for the feedback text area.
  • UI Enhancements: Improve the form’s appearance and user experience with CSS styling, using a CSS framework (like Bootstrap or Tailwind CSS) to make the form more attractive and responsive.
  • Accessibility: Ensure the form is accessible to users with disabilities by using semantic HTML, ARIA attributes, and providing keyboard navigation.
  • Error Handling Improvements: Handle network errors when submitting the form to the server, and display appropriate error messages to the user.
  • CAPTCHA: Add a CAPTCHA (Completely Automated Public Turing test to tell Computers and Humans Apart) to prevent spam submissions.

Common Mistakes and How to Fix Them

Here are some common mistakes and how to fix them:

  • Incorrect Element Types: If you get an error like “Property ‘value’ does not exist on type ‘HTMLElement’”, it’s likely that you haven’t correctly cast the element to its specific type. Use type assertions (e.g., `as HTMLInputElement`) to tell TypeScript the correct type.
  • Missing Event Prevention: If the form reloads the page after submitting, you’re not preventing the default form submission behavior. Use `event.preventDefault()` in your `handleSubmit` function.
  • Incorrect Path to Compiled JavaScript: Double-check the path to your compiled JavaScript file in the `<script src=”…”>` tag in your `index.html` file. Make sure it points to the correct location (e.g., `dist/index.js`).
  • Typos: TypeScript can catch many typos, but make sure you are using the correct variable names, function names, and property names.
  • Not Handling Null Values: If you are using `document.getElementById()`, the element might not be found, and it could return null. Make sure to check for null values before accessing the element’s properties or methods.

Key Takeaways

  • TypeScript enhances JavaScript development by adding static typing, improving code readability, and catching errors early.
  • Building a web-based feedback form is a practical example of how to use TypeScript in a real-world scenario.
  • You can extend the basic form with server-side integration, more input validation, UI enhancements, and accessibility features.
  • Always validate user input to prevent security vulnerabilities and ensure data integrity.

FAQ

Here are some frequently asked questions:

  1. What is TypeScript? TypeScript is a superset of JavaScript that adds static typing. It allows you to write more robust and maintainable code by catching errors early and providing better tooling support.
  2. Why use TypeScript for this project? TypeScript helps improve code quality, readability, and maintainability. It also provides better tooling support, such as autocompletion and error checking, which can speed up development.
  3. How do I deploy this form to a website? You’ll need to deploy the HTML, CSS, and JavaScript files to a web server. You’ll also need a server-side endpoint to handle the form submissions.
  4. Can I use a JavaScript framework like React or Angular with this approach? Yes, TypeScript works very well with modern JavaScript frameworks like React, Angular, and Vue.js. You can use TypeScript to write your components and manage your application’s state.
  5. How can I handle form submissions securely? Never trust data from the client-side. Always validate and sanitize user input on the server-side to prevent security vulnerabilities, such as cross-site scripting (XSS) and SQL injection attacks. Use HTTPS to encrypt the data transmitted between the client and the server.

This tutorial provides a solid foundation for building a web-based feedback form with TypeScript. By implementing this form, you can gather valuable user insights and improve your projects. Remember to validate user input on the server-side to prevent security vulnerabilities, and consider adding server-side integration for more complex features. With a little extra effort, you can create a truly useful tool to enhance your applications and understand your users better. The skills learned in this project are transferable and can be applied to a wide range of web development tasks, highlighting the importance of understanding TypeScript and its benefits for modern web development practices.