Astro Comment Form: with Turnstile & Prerender

This page summarizes the projects mentioned and recommended in the original post on dev.to

SurveyJS - Open-Source JSON Form Builder to Create Dynamic Forms Right in Your App
With SurveyJS form UI libraries, you can build and style forms in a fully-integrated drag & drop form builder, render them in your JS app, and store form submission data in any backend, inc. PHP, ASP.NET Core, and Node.js.
surveyjs.io
featured
InfluxDB - Power Real-Time Data Analytics at Scale
Get real-time insights from all types of time series data with InfluxDB. Ingest, query, and analyze billions of data points in real-time with unbounded cardinality.
www.influxdata.com
featured
  • astro

    Code to accompany Astro articles. (by rodneylab)

  • Name Email Comment Submit

    Enter fullscreen mode Exit fullscreen mode

    You see the Turnstile code we needed to add is minimal. We add a script tag in the HTML head section (line 7). Then, the little widget which shows up below the submit button (line 25).

    We are using the platform here; we use built-in JavaScript APIs to submit the form. You will see the form has ${siteUrl}/api/message as the action. That is the route we will set the form handler to listen on.

    Astro Comment Form: Screen capture shows comment form with name, email and comment fields. Below the submit button you can see the Turnstile widget with a tick or check mark and the word success.

    Turnstile Verification Process

    When a user visits the page, the widget runs in the background and decides if the user is a bot or not (traditionally a user challenge would have been used here). The script sends data from the client browser to Cloudflare. Cloudflare then responds with a code. We use that code server-side to check if the visitor passed the Captcha (more on that later). The Turnstile JavaScript code we added will automatically add an extra field with that response code. This is how we get the code from client to server.

    Form Styling

    Spruce up the form a touch with some extra styles at the bottom of src/components/CommentForm.svelte:

    
        button {
            all: unset;
            cursor: pointer;
            background-color: var(--colour-light);
            color: var(--colour-brand);
            padding: var(--spacing-2);
            margin-bottom: var(--spacing-6);
            font-size: var(--font-size-3);
            font-weight: var(--font-weight-bold);
            text-align: center;
        }
    
        button:focus {
            outline: var(--spacing-px-2) solid var(--colour-alt);
        }
    
        button:focus,
        button:hover {
            background-color: var(--colour-light-alpha-90);
        }
    
        textarea {
            resize: none;
        }
    
        button,
        input,
        textarea {
            border-radius: var(--spacing-1);
        }
    
        input,
        textarea {
            text-indent: var(--spacing-2);
            line-height: 1.75;
            margin-bottom: var(--spacing-4);
            border-radius: var(--spacing-1);
            border-style: none;
            font-size: var(--font-size-2);
        }
    
        .cf-turnstile {
            margin-left: auto;
        }
    
    
    Enter fullscreen mode Exit fullscreen mode

    🥹 Thank you Page

    Before we jump to the form handler, let’s add a thank you page. We will show this on successful form completion. Create src/pages/thanks.astro with this content:

    ---
    import Layout from '~layouts/Layout.astro';
    
    export const prerender = true;
    ---
    
    
        
            

    Thanks for submitting your comment!

    We will be in touch

    body { background-color: var(--colour-theme); color: var(--colour-dark); }
    Enter fullscreen mode Exit fullscreen mode

    🍶 Server-Side Form Handler

    We are on the home straight now. Once we add the form handler, all we will have left to do is test! In Astro, API routes follow the same file-based routing system as HTML pages. The main difference is that the file extensions are different. Create a src/pages/api folder and in there, add message.ts with the following content:

    import type { APIRoute } from 'astro';
    
    const siteUrl = import.meta.env.PUBLIC_SITE_URL;
    const turnstileSecret = import.meta.env.TURNSTILE_SECRETKEY;
    
    export const post: APIRoute = async function post({ redirect, request }) {
        try {
            const form = await request.formData();
            const name = form.get('name');
            const email = form.get('email');
            const comment = form.get('comment');
            const turnstileResponse = form.get('cf-turnstile-response');
    
            const ip = request.headers.get('CF-Connecting-IP');
    
            if (typeof turnstileResponse === 'string') {
                const bodyFormData = new FormData();
                bodyFormData.append('secret', turnstileSecret);
                bodyFormData.append('response', turnstileResponse);
                ip && bodyFormData.append('remoteip', ip);
                const response = await fetch('https://challenges.cloudflare.com/turnstile/v0/siteverify', {
                    method: 'POST',
                    body: bodyFormData,
                });
                const { success } = await response.json();
    
                console.log({ name, email, comment, success });
            }
    
            return redirect(`${siteUrl}/thanks`);
        } catch (error: unknown) {
            console.error(`Error in comment form submission: ${error as string}`);
            return redirect(`${siteUrl}/`);
        }
    };
    
    Enter fullscreen mode Exit fullscreen mode

    Again we are using standard JavaScript APIs for form handling. Remember we said Turnstile adds an extra form field for us? We pull this in in line 12. The final part of the verification process is to send the client response to Cloudflare, along with our secret Turnstile API key. The server replies with a JSON object including a success field. As you might expect this is false when Turnstile assesses the visitor to be a bot and true otherwise.

    In a real world app, when success is true we would want to commit the comment data to our database as well as any other processing needed. We just do a console log here instead. Also in a production app, we should want to do some sanitisation before inserting the data to the database. On top we would have some validation so we do not commit junk to the database. If the comments will be displayed publicly you will also need to filter them checking for inappropriate user-submitted content.

    Returning to our basic example, finally we respond with a redirect pushing the visitor browser to our new Thank You page (line 30).

    💯 Astro Comment Form: Testing

    Try submitting the form from your dev server. If all goes well, you should see the Thank You page.

    Astro Comment Form: Screen capture shows success page, thanking the visitor for leaving a comment.

    To build the site locally we need to run in a Cloudflare wrangler environment. Add an extra script to the project package.json file to handle this:

    {
        "name": "astro-prerender-comment-form",
        "type": "module",
        "version": "0.0.1",
        "private": true,
        "scripts": {
            "dev": "astro dev",
            "start": "astro dev",
            "build": "astro telemetry disable && astro build",
            "preview": "astro preview",
            "preview:cf": "wrangler pages dev ./dist",
        },
        // TRUNCATED...
    
    Enter fullscreen mode Exit fullscreen mode

    Then run the script from the Terminal:

    pnpm preview:cf
    
    Enter fullscreen mode Exit fullscreen mode

    This time the site will be available at http://localhost:8788. If this is your first time running wrangler from your machine, follow the instructions in the Terminal to log in.

    Remember to update PUBLIC_SITE_URL in your .env file to match the new URL (otherwise the form will not submit as expected).

    That’s it! You can now try pushing to Cloudflare Pages. Create a set of Turnstile credentials for you actual public domain first.

    🙌🏽 Astro Comment Form: Wrapping Up

    In this post, we saw how you can add a server-side form handler to your static Astro site. In particular we saw:

    • how to add Turnstile Captcha in Astro,
    • how Astro Hybrid rendering and prerendering work,
    • some points to consider in a full production comment form.

    You can see the full code for this project in the Rodney Lab GitHub repo. I do hope you have found this post useful! I am keen to hear what you are doing with Astro and ideas for future projects. Also let me know about any possible improvements to the content above.

    🙏🏽 Astro Comment Form: Feedback

    Have you found the post useful? Would you prefer to see posts on another topic instead? Get in touch with ideas for new posts. Also if you like my writing style, get in touch if I can write some posts for your company site on a consultancy basis. Read on to find ways to get in touch, further below. If you want to support posts similar to this one and can spare a few dollars, euros or pounds, please consider supporting me through Buy me a Coffee.

    Finally, feel free to share the post on your social media accounts for all your followers who will find it useful. As well as leaving a comment below, you can get in touch via @askRodney on Twitter, @[email protected] on Mastodon and also the #rodney Element Matrix room. Also, see further ways to get in touch with Rodney Lab. I post regularly on Astro as well as SEO. Also subscribe to the newsletter to keep up-to-date with our latest projects.

  • matrix.to

    A simple stateless privacy-protecting URL redirecting service for Matrix

  • Name Email Comment Submit

    Enter fullscreen mode Exit fullscreen mode

    You see the Turnstile code we needed to add is minimal. We add a script tag in the HTML head section (line 7). Then, the little widget which shows up below the submit button (line 25).

    We are using the platform here; we use built-in JavaScript APIs to submit the form. You will see the form has ${siteUrl}/api/message as the action. That is the route we will set the form handler to listen on.

    Astro Comment Form: Screen capture shows comment form with name, email and comment fields. Below the submit button you can see the Turnstile widget with a tick or check mark and the word success.

    Turnstile Verification Process

    When a user visits the page, the widget runs in the background and decides if the user is a bot or not (traditionally a user challenge would have been used here). The script sends data from the client browser to Cloudflare. Cloudflare then responds with a code. We use that code server-side to check if the visitor passed the Captcha (more on that later). The Turnstile JavaScript code we added will automatically add an extra field with that response code. This is how we get the code from client to server.

    Form Styling

    Spruce up the form a touch with some extra styles at the bottom of src/components/CommentForm.svelte:

    
        button {
            all: unset;
            cursor: pointer;
            background-color: var(--colour-light);
            color: var(--colour-brand);
            padding: var(--spacing-2);
            margin-bottom: var(--spacing-6);
            font-size: var(--font-size-3);
            font-weight: var(--font-weight-bold);
            text-align: center;
        }
    
        button:focus {
            outline: var(--spacing-px-2) solid var(--colour-alt);
        }
    
        button:focus,
        button:hover {
            background-color: var(--colour-light-alpha-90);
        }
    
        textarea {
            resize: none;
        }
    
        button,
        input,
        textarea {
            border-radius: var(--spacing-1);
        }
    
        input,
        textarea {
            text-indent: var(--spacing-2);
            line-height: 1.75;
            margin-bottom: var(--spacing-4);
            border-radius: var(--spacing-1);
            border-style: none;
            font-size: var(--font-size-2);
        }
    
        .cf-turnstile {
            margin-left: auto;
        }
    
    
    Enter fullscreen mode Exit fullscreen mode

    🥹 Thank you Page

    Before we jump to the form handler, let’s add a thank you page. We will show this on successful form completion. Create src/pages/thanks.astro with this content:

    ---
    import Layout from '~layouts/Layout.astro';
    
    export const prerender = true;
    ---
    
    
        
            

    Thanks for submitting your comment!

    We will be in touch

    body { background-color: var(--colour-theme); color: var(--colour-dark); }
    Enter fullscreen mode Exit fullscreen mode

    🍶 Server-Side Form Handler

    We are on the home straight now. Once we add the form handler, all we will have left to do is test! In Astro, API routes follow the same file-based routing system as HTML pages. The main difference is that the file extensions are different. Create a src/pages/api folder and in there, add message.ts with the following content:

    import type { APIRoute } from 'astro';
    
    const siteUrl = import.meta.env.PUBLIC_SITE_URL;
    const turnstileSecret = import.meta.env.TURNSTILE_SECRETKEY;
    
    export const post: APIRoute = async function post({ redirect, request }) {
        try {
            const form = await request.formData();
            const name = form.get('name');
            const email = form.get('email');
            const comment = form.get('comment');
            const turnstileResponse = form.get('cf-turnstile-response');
    
            const ip = request.headers.get('CF-Connecting-IP');
    
            if (typeof turnstileResponse === 'string') {
                const bodyFormData = new FormData();
                bodyFormData.append('secret', turnstileSecret);
                bodyFormData.append('response', turnstileResponse);
                ip && bodyFormData.append('remoteip', ip);
                const response = await fetch('https://challenges.cloudflare.com/turnstile/v0/siteverify', {
                    method: 'POST',
                    body: bodyFormData,
                });
                const { success } = await response.json();
    
                console.log({ name, email, comment, success });
            }
    
            return redirect(`${siteUrl}/thanks`);
        } catch (error: unknown) {
            console.error(`Error in comment form submission: ${error as string}`);
            return redirect(`${siteUrl}/`);
        }
    };
    
    Enter fullscreen mode Exit fullscreen mode

    Again we are using standard JavaScript APIs for form handling. Remember we said Turnstile adds an extra form field for us? We pull this in in line 12. The final part of the verification process is to send the client response to Cloudflare, along with our secret Turnstile API key. The server replies with a JSON object including a success field. As you might expect this is false when Turnstile assesses the visitor to be a bot and true otherwise.

    In a real world app, when success is true we would want to commit the comment data to our database as well as any other processing needed. We just do a console log here instead. Also in a production app, we should want to do some sanitisation before inserting the data to the database. On top we would have some validation so we do not commit junk to the database. If the comments will be displayed publicly you will also need to filter them checking for inappropriate user-submitted content.

    Returning to our basic example, finally we respond with a redirect pushing the visitor browser to our new Thank You page (line 30).

    💯 Astro Comment Form: Testing

    Try submitting the form from your dev server. If all goes well, you should see the Thank You page.

    Astro Comment Form: Screen capture shows success page, thanking the visitor for leaving a comment.

    To build the site locally we need to run in a Cloudflare wrangler environment. Add an extra script to the project package.json file to handle this:

    {
        "name": "astro-prerender-comment-form",
        "type": "module",
        "version": "0.0.1",
        "private": true,
        "scripts": {
            "dev": "astro dev",
            "start": "astro dev",
            "build": "astro telemetry disable && astro build",
            "preview": "astro preview",
            "preview:cf": "wrangler pages dev ./dist",
        },
        // TRUNCATED...
    
    Enter fullscreen mode Exit fullscreen mode

    Then run the script from the Terminal:

    pnpm preview:cf
    
    Enter fullscreen mode Exit fullscreen mode

    This time the site will be available at http://localhost:8788. If this is your first time running wrangler from your machine, follow the instructions in the Terminal to log in.

    Remember to update PUBLIC_SITE_URL in your .env file to match the new URL (otherwise the form will not submit as expected).

    That’s it! You can now try pushing to Cloudflare Pages. Create a set of Turnstile credentials for you actual public domain first.

    🙌🏽 Astro Comment Form: Wrapping Up

    In this post, we saw how you can add a server-side form handler to your static Astro site. In particular we saw:

    • how to add Turnstile Captcha in Astro,
    • how Astro Hybrid rendering and prerendering work,
    • some points to consider in a full production comment form.

    You can see the full code for this project in the Rodney Lab GitHub repo. I do hope you have found this post useful! I am keen to hear what you are doing with Astro and ideas for future projects. Also let me know about any possible improvements to the content above.

    🙏🏽 Astro Comment Form: Feedback

    Have you found the post useful? Would you prefer to see posts on another topic instead? Get in touch with ideas for new posts. Also if you like my writing style, get in touch if I can write some posts for your company site on a consultancy basis. Read on to find ways to get in touch, further below. If you want to support posts similar to this one and can spare a few dollars, euros or pounds, please consider supporting me through Buy me a Coffee.

    Finally, feel free to share the post on your social media accounts for all your followers who will find it useful. As well as leaving a comment below, you can get in touch via @askRodney on Twitter, @[email protected] on Mastodon and also the #rodney Element Matrix room. Also, see further ways to get in touch with Rodney Lab. I post regularly on Astro as well as SEO. Also subscribe to the newsletter to keep up-to-date with our latest projects.

  • SurveyJS

    Open-Source JSON Form Builder to Create Dynamic Forms Right in Your App. With SurveyJS form UI libraries, you can build and style forms in a fully-integrated drag & drop form builder, render them in your JS app, and store form submission data in any backend, inc. PHP, ASP.NET Core, and Node.js.

    SurveyJS logo
NOTE: The number of mentions on this list indicates mentions on common posts plus user suggested alternatives. Hence, a higher number means a more popular project.

Suggest a related project

Related posts

  • Astro Vanilla-Extract Styling: CSS in TypeScript

    1 project | dev.to | 2 Jan 2023
  • Astro JS Mux Video: using Custom Elements

    1 project | dev.to | 15 Aug 2022
  • Temporal API Duration: Working with Time Periods

    1 project | dev.to | 8 Aug 2022
  • Astro JS Tutorial: Quick Start Astro Guide

    1 project | dev.to | 18 Apr 2022
  • Astro Landing Page Form: Netlify Serverless Contact Form

    1 project | dev.to | 5 Apr 2022