PHPackages                             reecem/static-form - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. reecem/static-form

ActiveLibrary[API Development](/categories/api)

reecem/static-form
==================

Handle static form submissions in Laravel app

v0.2.1(3y ago)382MITPHPPHP ^7.3|^8.0CI failing

Since Mar 9Pushed 3y ago1 watchersCompare

[ Source](https://github.com/ReeceM/static-form)[ Packagist](https://packagist.org/packages/reecem/static-form)[ Docs](https://static-form.laravelpkg.dev)[ Fund](https://www.buymeacoffee.com/ReeceM)[ Fund](https://www.paypal.me/iexistin3d)[ RSS](/packages/reecem-static-form/feed)WikiDiscussions master Synced 1w ago

READMEChangelog (3)Dependencies (4)Versions (5)Used By (0)

Handle static form submissions and other static site things in Laravel app
==========================================================================

[](#handle-static-form-submissions-and-other-static-site-things-in-laravel-app)

[![Latest Version on Packagist](https://camo.githubusercontent.com/d3315b6a6c0c568618ee57dcdff579b6fd92fe8347275870117b5c944667fe42/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f72656563656d2f7374617469632d666f726d2e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/reecem/static-form)[![PHPUnit Tests](https://github.com/ReeceM/static-form/actions/workflows/run-tests.yml/badge.svg)](https://github.com/ReeceM/static-form/actions/workflows/run-tests.yml)[![Total Downloads](https://camo.githubusercontent.com/f103049fcab10b7d7546edabaa090c716d392059d668b6ccad66fda534975ba5/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f72656563656d2f7374617469632d666f726d2e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/reecem/static-form)[![Styling](https://github.com/ReeceM/static-form/actions/workflows/php-cs-fixer.yml/badge.svg)](https://github.com/ReeceM/static-form/actions/workflows/php-cs-fixer.yml)

[![](https://camo.githubusercontent.com/71b5a42b689c7a6682c35eb485249798e7e106020f67eee70ee5e8bc79605847/68747470733a2f2f62616e6e6572732e6265796f6e64636f2e64652f537461746963253230466f726d2e706e673f7468656d653d6461726b267061636b6167654d616e616765723d636f6d706f7365722b72657175697265267061636b6167654e616d653d72656563656d2532467374617469632d666f726d267061747465726e3d78457175616c73267374796c653d7374796c655f32266465736372697074696f6e3d48616e646c652b5374617469632b536974652b666f726d732b7375626d697373696f6e732b696e736964652b796f75722b4c61726176656c2b417070266d643d312673686f7757617465726d61726b3d3126666f6e7453697a653d313030707826696d616765733d6d61696c267769647468733d37303026686569676874733d343030)](https://github.com/reecem/static-from#readme)

Handle Static form submissions inside your Laravel app from Next.JS and Netlify or any other static site server.

Installation
------------

[](#installation)

You can install the package via composer:

```
composer require reecem/static-form
```

To install the application you can do the following:

```
php artisan static-form:install --provider --config
```

This will install the config file and the service provider, you can though opt for each one separately or use the following:

You can publish the config file with:

```
php artisan vendor:publish --provider="ReeceM\StaticForm\StaticFormServiceProvider" --tag="static-form-config"
```

You can publish the Service Provider file with:

```
php artisan vendor:publish --provider="ReeceM\StaticForm\StaticFormServiceProvider" --tag="static-form-provider"
```

You will need to add the following to the `config/app.php` file:

```
        /*
         * Package Service Providers...
         */
+        App\Providers\StaticFormServiceProvider::class
```

You can view the docs here

Usage
-----

[](#usage)

As an overview, the usage of the current version is that you can use the packages middleware on controllers that you define, this will then use your controller to handle the request data.

### Create The Token

[](#create-the-token)

The first step is to generate your token, to do that you can use the console command:

```
php artisan static-form --refresh
```

This will generate your token, it will show you the plain text version only during that session.

The other way is to call the API endpoint to generate a new one. The API is secured via the Gate that is defined in the `App\Providers\StaticFormServiceProvider::class`

You can define any logic in there that would allow only authorized people to access the application.

To call the API endpoint, for now you can make a request to the endpoint through a custom UI and javascript code.

MethodEndpointDescriptionGETdomain.tld/api/static-form/tokenThis will return a 200 status and the static-form package version if the toke is foundPOSTPATCHdomain.tld/api/static-form/tokenThe url part that says `static-form` can be changed and comes from the config key `static-form.path`

The response for creating a token would be the following JSON with a 201 status:

```
{
    "plain_token": "random_string_that_is_40_characters_long",
    "message": "Token Created, please keep this as it is available once"
}
```

- Make a plugin UI, just deciding on if it should be in package or a separate snippet.

### Use the Middleware

[](#use-the-middleware)

To use the middleware, you can define a route using the config file, I do suggest that you use the API endpoint, this is as it is stateless and also would not require the CSRF token.

```
// routes/api.php

Route::group([
    'middleware' => config('static-form.middleware.forms'),
], function () {
    // A controller that you have created.
    Route::post('/contact', StaticContactController::class)->name('contact.create');
});
```

### Submitting Forms

[](#submitting-forms)

On your static site, you can have your contact form. The way of handling the form is done using the API part of the hosting provider.

So for Vercel apps, you can create a new file under the `api` directory.

For the API part of the code:

```
// api/contactus.js

/**
 * Create a contact request to the main server.
 *
 * @param {http.IncomingMessage} req
 * @param {*} res
 */
import { APP_TOKEN, APP_URL } from "../../../lib/constants"

export default async function contactus(req, res) {

  if (req.method !== 'POST') {
    return res.status(400);
  }

  if (req.body?.website) {
    return res.status(200);
  }

  let body = JSON.parse(req.body)
  let {_token, xsrf} = body.token;
  delete body.token

  const request = await fetch(
    `${APP_URL}/api/static-form/contactus`,
    {
      method: 'POST',
      body: JSON.stringify(body),
      headers: {
        'X-STATIC-FORM': APP_TOKEN,
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        "x-requested-with": "XMLHttpRequest",
      },
    }
  )

  if (request.status !== 201 ) {
    let json = await request.json()

    throw new Error(json.message || 'Failed to fetch API');
  }

  const json = await request.json()

  if (json.errors) {
    console.error(json.errors)
    throw new Error('Failed to fetch API, json errors')
  }

  return res.status(201).json(json.data ?? {});
}
```

You can try a simple form layout for the frontend:

```
import React, { useCallback, useEffect, useRef, useState } from 'react'

const ContactUs = () => {
    const [contactName, setContactName] = useState('')
    const [contactEmail, setContactEmail] = useState('')
    const [honey, setHoney] = useState('')

    function handleForm(e) {
        e.preventDefault()

        if (honey.length >= 1) {
            return
        }

        let body = {
            name: contactName,
            email: contactEmail,
        }

        fetch(
            `${location.origin}/api/contactus`,
            {
                method: 'POST',
                body: JSON.stringify(body)
            }
        )
        .then(response => {
            console.debug(response);
        })
        .catch(error => {
            console.error(error)
        })
    }

    return (

                    Name
                     setContactName(e.target.value)}
                        placeholder="Your Name"
                        type="text"
                    />

                    Email
                     setContactEmail(e.target.value)}
                        placeholder="Your email"
                        type="email"
                    />

                 setHoney(e.target.value)}>
                Submit

    )
}

export default ContactUs;
```

Testing
-------

[](#testing)

Testing is currently a work in progress, there are some :), I am manually testing it in an actual application to make sure it works though.

```
composer test
```

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING](.github/CONTRIBUTING.md) for details.

Security Vulnerabilities
------------------------

[](#security-vulnerabilities)

Please review [our security policy](../../security/policy) on how to report security vulnerabilities.

Credits
-------

[](#credits)

- [ReeceM](https://github.com/ReeceM)
- [All Contributors](../../contributors)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

25

—

LowBetter than 37% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity10

Limited adoption so far

Community11

Small or concentrated contributor base

Maturity51

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 96.9% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~259 days

Total

3

Last Release

1379d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/fd867a157c363b8ad2bb8a082e65808b097a8297ecba71fda5520fb5d8cf0734?d=identicon)[ReeceM](/maintainers/ReeceM)

---

Top Contributors

[![ReeceM](https://avatars.githubusercontent.com/u/2767904?v=4)](https://github.com/ReeceM "ReeceM (31 commits)")[![LarsWiegers](https://avatars.githubusercontent.com/u/20204608?v=4)](https://github.com/LarsWiegers "LarsWiegers (1 commits)")

---

Tags

apiformformslaravelnetlifynextjspackagelaravelnetlifynext.jsstatic formsstatic site forms

###  Code Quality

TestsPHPUnit

Static AnalysisPsalm

Type Coverage Yes

### Embed Badge

![Health badge](/badges/reecem-static-form/health.svg)

```
[![Health](https://phpackages.com/badges/reecem-static-form/health.svg)](https://phpackages.com/packages/reecem-static-form)
```

###  Alternatives

[andreaselia/laravel-api-to-postman

Generate a Postman collection automatically from your Laravel API

1.0k586.2k3](/packages/andreaselia-laravel-api-to-postman)[mll-lab/laravel-graphiql

Easily integrate GraphiQL into your Laravel project

683.2M9](/packages/mll-lab-laravel-graphiql)[scalar/laravel

Render your OpenAPI-based API reference

6183.9k2](/packages/scalar-laravel)[ryangjchandler/bearer

Minimalistic token-based authentication for Laravel API endpoints.

8129.8k](/packages/ryangjchandler-bearer)[combindma/laravel-facebook-pixel

Meta pixel integration for Laravel

4956.9k](/packages/combindma-laravel-facebook-pixel)[stechstudio/laravel-hubspot

A Laravel SDK for the HubSpot CRM Api

2971.0k](/packages/stechstudio-laravel-hubspot)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
