-
Notifications
You must be signed in to change notification settings - Fork 16
Add formspree-ajax #79
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 26 commits
f770476
9f16451
356b0d0
501bd59
394c496
aca9c24
6f9d4d6
faa6db8
9a429b4
f4f32c1
c598308
ed52837
ae79c2d
3518cdb
d01623c
ab35664
151bd91
53df0e8
d52a635
3061d5c
43a7d7e
ed4d954
b7478e8
604304f
291e86f
7099f25
edc9e6a
a835837
694ef99
0baa22d
9c95b08
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| '@formspree/ajax': major | ||
| --- | ||
|
|
||
| add formspree-ajax |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -31,4 +31,11 @@ yarn-error.log* | |
| # turbo | ||
| .turbo | ||
|
|
||
| .vscode | ||
| .vscode | ||
|
|
||
| .local-dev | ||
|
|
||
| .claude | ||
|
|
||
| # playwright | ||
| .playwright-mcp | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| # CLAUDE.md | ||
|
|
||
| This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. | ||
|
|
||
| ## Build and Development Commands | ||
|
|
||
| ```sh | ||
| yarn # Install dependencies | ||
| yarn build # Build all packages (required before dev) | ||
| yarn dev # Run dev server with cra-demo example on localhost:3000 | ||
| yarn test # Run tests across all packages | ||
| yarn typecheck # Type check all packages | ||
| yarn lint # Lint all packages | ||
| yarn format # Format code with Prettier | ||
| yarn changeset # Create a changeset for PRs | ||
| ``` | ||
|
|
||
| ### Package-specific commands | ||
|
|
||
| Run from package directory (e.g., `packages/formspree-core`): | ||
|
|
||
| ```sh | ||
| yarn test # Run tests for this package | ||
| yarn build # Build this package only | ||
| yarn lint # Lint this package | ||
| ``` | ||
|
|
||
| For the ajax package specifically: | ||
|
|
||
| ```sh | ||
| yarn demo # Build and run ajax-demo example (from packages/formspree-ajax) | ||
| ``` | ||
|
|
||
| ## Architecture | ||
|
|
||
| This is a Yarn workspaces monorepo managed by Turborepo with three packages: | ||
|
|
||
| - **@formspree/core** - Core submission client and types. Provides `createClient`, `getDefaultClient`, `SubmissionError`, and submission types. | ||
| - **@formspree/react** - React hooks (`useForm`, `useSubmit`) built on top of core. Depends on core. | ||
| - **@formspree/ajax** - Vanilla JS library for declarative form handling. Recreation of [statickit-html](https://github.com/formspree/statickit-html) using core. | ||
|
|
||
| All packages use `tsup` for building and output to `dist/`. | ||
|
|
||
| ## @formspree/ajax Package Guidelines | ||
|
|
||
| Reference API from statickit-html: | ||
|
|
||
| - `onSubmit(config)` - called before submission | ||
| - `onSuccess(config, response)` - called on successful submission | ||
| - `onError(config, errors)` - called on validation errors | ||
| - `onFailure(config, exception)` - called on unexpected errors | ||
| - `onInit(config)` - called when form is initialized | ||
|
|
||
| The `config` object contains: form element, form identifiers, data, debug flag, fields config, and client. | ||
|
|
||
| ## Documentation | ||
|
|
||
| - Add JSDoc comments to all TypeScript types, interfaces, and their properties | ||
| - Include `@template` tags for generic types | ||
| - Include `@param` tags for callback parameters |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,13 +1,13 @@ | ||
| # Formspree JS | ||
|
|
||
| A monorepo containing libraries for seamless form integration with [Formspree](https://formspree.io/) via Javascript and/or React. | ||
| A monorepo containing libraries for seamless form integration with [Formspree](https://formspree.io/) via JavaScript and/or React. | ||
|
|
||
| ## Installation | ||
|
|
||
| The core and react packages can be installed using your package manager of choice. | ||
| ## Packages | ||
|
|
||
| ### `@formspree/core` | ||
|
|
||
| Core submission client and types. Provides `createClient`, `getDefaultClient`, `SubmissionError`, and submission types. | ||
|
|
||
| ```sh | ||
| npm install @formspree/core | ||
|
|
||
|
|
@@ -18,9 +18,9 @@ pnpm add @formspree/core | |
|
|
||
| ### `@formspree/react` | ||
|
|
||
| **Prerequisites** | ||
| React hooks (`useForm`, `useSubmit`) and components (`ValidationError`) built on top of core. | ||
|
|
||
| - React 16.8 or higher. | ||
| **Prerequisites:** React 16.8 or higher. | ||
|
|
||
| ```sh | ||
| npm install @formspree/react | ||
|
|
@@ -30,7 +30,35 @@ yarn add @formspree/react | |
| pnpm add @formspree/react | ||
| ``` | ||
|
|
||
| _Note: `@formspree/core` is a dependency of `@formspree/react`, so you don't need to install `@formspree/core` separately._ | ||
| _Note: `@formspree/core` is a dependency of `@formspree/react`, so you don't need to install it separately._ | ||
|
|
||
| ### `@formspree/ajax` | ||
|
|
||
| Vanilla JavaScript library for declarative form handling with plain HTML forms. No framework required — use data attributes and a single `initForm()` call, or load via a script tag with the `window.formspree()` global API. | ||
|
|
||
| ```sh | ||
| npm install @formspree/ajax | ||
|
|
||
| yarn add @formspree/ajax | ||
| ``` | ||
|
|
||
| _Note: `@formspree/core` is a dependency of `@formspree/ajax`, so you don't need to install it separately._ | ||
|
|
||
| Or via CDN (no bundler needed): | ||
|
|
||
| ```html | ||
| <script> | ||
| window.formspree = | ||
| window.formspree || | ||
| function () { | ||
| (formspree.q = formspree.q || []).push(arguments); | ||
| }; | ||
| formspree('initForm', { formElement: '#my-form', formId: 'YOUR_FORM_ID' }); | ||
| </script> | ||
| <script src="https://unpkg.com/@formspree/ajax@1/dist/global.js" defer></script> | ||
|
||
| ``` | ||
|
|
||
| See the [@formspree/ajax README](./packages/formspree-ajax/README.md) for full documentation. | ||
|
|
||
| ## Help and Support | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| # Formspree Configuration | ||
| # Copy this file to .env.local and add your form ID | ||
| VITE_FORMSPREE_FORM_ID=YOUR_FORM_ID |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| root: true | ||
| extends: | ||
| - '../../.eslintrc.yml' | ||
| parserOptions: | ||
| project: './tsconfig.json' |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,125 @@ | ||
| # Formspree AJAX Demo | ||
|
|
||
| A pure JavaScript/TypeScript example demonstrating how to use `@formspree/ajax` for form submissions without any frontend framework. | ||
|
|
||
| ## Features | ||
|
|
||
| - Pure HTML/CSS/TypeScript implementation | ||
| - No React, Vue, or other framework dependencies | ||
| - Beautiful, responsive contact form UI | ||
| - Loading states and error handling | ||
| - Form validation feedback | ||
| - Success/error messages | ||
| - Built with Vite for fast development | ||
|
|
||
| ## Setup | ||
|
|
||
| 1. Install dependencies: | ||
|
|
||
| ```bash | ||
| yarn install | ||
| ``` | ||
|
|
||
| 2. Get your Formspree form ID: | ||
|
|
||
| - Go to [formspree.io](https://formspree.io) | ||
| - Create a new form or use an existing one | ||
| - Copy your form ID (e.g., `xyzabc123`) | ||
|
|
||
| 3. Create a `.env.local` file from the template: | ||
|
|
||
| ```bash | ||
| cp .env.local.template .env.local | ||
| ``` | ||
|
|
||
| 4. Update `VITE_FORMSPREE_FORM_ID` in `.env.local` with your form ID. | ||
|
|
||
| ## Development | ||
|
|
||
| Run the development server: | ||
|
|
||
| ```bash | ||
| yarn dev | ||
| ``` | ||
|
|
||
| The demo will be available at `http://localhost:5173` | ||
|
|
||
| ## Build | ||
|
|
||
| Build for production: | ||
|
|
||
| ```bash | ||
| yarn build | ||
| ``` | ||
|
|
||
| The output will be in the `dist` directory. | ||
|
|
||
| ## Usage | ||
|
|
||
| ### Basic Form Initialization | ||
|
|
||
| ```typescript | ||
| import { initForm } from '@formspree/ajax'; | ||
|
|
||
| initForm({ | ||
| formElement: '#contact-form', | ||
| formId: 'your-form-id', | ||
| onSuccess: ({ form }) => { | ||
| console.log('Success!'); | ||
| form.reset(); | ||
| }, | ||
| onError: (_context, error) => { | ||
| const messages = error.getFormErrors().map((e) => e.message); | ||
| console.error('Validation errors:', messages); | ||
| }, | ||
| onFailure: (_context, error) => { | ||
| console.error('Unexpected error:', error); | ||
| }, | ||
| }); | ||
| ``` | ||
|
|
||
| ### With Extra Data | ||
|
|
||
| ```typescript | ||
| initForm({ | ||
| formElement: '#contact-form', | ||
| formId: 'your-form-id', | ||
| data: { | ||
| source: 'website', | ||
| timestamp: new Date().toISOString(), | ||
| }, | ||
| onSuccess: ({ form }) => { | ||
| form.reset(); | ||
| }, | ||
| }); | ||
| ``` | ||
|
|
||
| ### Custom Origin (e.g., staging) | ||
|
|
||
| ```typescript | ||
| initForm({ | ||
| formElement: '#contact-form', | ||
| formId: 'your-form-id', | ||
| origin: 'https://staging.formspree.io', | ||
| debug: true, | ||
| }); | ||
| ``` | ||
|
|
||
| ## File Structure | ||
|
|
||
| ``` | ||
| ajax-demo/ | ||
| ├── public/ | ||
| │ ├── index.html # HTML form with styling | ||
| │ └── main.ts # TypeScript implementation | ||
| ├── .env.local.template # Environment variables template | ||
| ├── package.json | ||
| ├── tsconfig.json | ||
| ├── vite.config.ts | ||
| └── README.md | ||
| ``` | ||
|
|
||
| ## Learn More | ||
|
|
||
| - [Formspree Documentation](https://help.formspree.io/) | ||
| - [@formspree/ajax Package](../../packages/formspree-ajax) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| { | ||
| "name": "@formspree/ajax-demo", | ||
| "version": "1.0.0", | ||
| "private": true, | ||
| "description": "Pure JavaScript AJAX example using Formspree", | ||
| "scripts": { | ||
| "build": "tsc && vite build", | ||
| "clean": "rm -rf dist && rm -rf node_modules", | ||
| "dev": "vite", | ||
| "preview": "vite preview" | ||
| }, | ||
| "dependencies": { | ||
| "@formspree/ajax": "*" | ||
| }, | ||
| "devDependencies": { | ||
| "typescript": "^5.0.0", | ||
| "vite": "^6.0.6" | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| // This file simulates loading dist/global.js in the Vite dev environment. | ||
| // In production, you'd use: <script src="https://unpkg.com/@formspree/ajax@1/dist/global.js" defer></script> | ||
| import '@formspree/ajax/global'; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| <!DOCTYPE html> | ||
| <html lang="en"> | ||
| <head> | ||
| <meta charset="UTF-8"> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
| <title>Formspree AJAX - CDN Demo</title> | ||
| <link rel="stylesheet" href="/styles.css"> | ||
| </head> | ||
| <body> | ||
| <div class="container"> | ||
| <a href="/index-packages.html" class="back-link">← Package Demo</a> | ||
|
|
||
| <h1>Contact Form <span class="badge">CDN</span></h1> | ||
| <p class="subtitle">Using <code>window.formspree()</code> global API — no bundler required</p> | ||
|
|
||
| <div data-fs-success>Thanks for reaching out! We'll get back to you soon.</div> | ||
| <div data-fs-error>Something went wrong. Please try again.</div> | ||
|
|
||
| <form id="contact-form"> | ||
| <div class="form-group"> | ||
| <label for="name">Name</label> | ||
| <input | ||
| type="text" | ||
| id="name" | ||
| name="name" | ||
| placeholder="Your name" | ||
| data-fs-field | ||
| > | ||
| <span data-fs-error="name"></span> | ||
| </div> | ||
|
|
||
| <div class="form-group"> | ||
| <label for="email">Email</label> | ||
| <input | ||
| type="email" | ||
| id="email" | ||
| name="email" | ||
| placeholder="your.email@example.com" | ||
| data-fs-field | ||
| > | ||
| <span data-fs-error="email"></span> | ||
| </div> | ||
|
|
||
| <div class="form-group"> | ||
| <label for="message">Message</label> | ||
| <textarea | ||
| id="message-field" | ||
| name="message" | ||
| placeholder="Write your message here..." | ||
| data-fs-field | ||
| ></textarea> | ||
| <span data-fs-error="message"></span> | ||
| </div> | ||
|
|
||
| <button type="submit" data-fs-submit-btn> | ||
| Send Message | ||
| </button> | ||
| </form> | ||
|
|
||
| <div class="note"> | ||
| <strong>How it works:</strong> Load <code>global.js</code> via a script tag. | ||
| It sets up <code>window.formspree()</code>, then call it to initialize your form. | ||
| No bundler needed! | ||
| </div> | ||
| </div> | ||
|
|
||
| <!-- | ||
| Production usage: | ||
|
|
||
| <script> | ||
| window.formspree=window.formspree||function(){(formspree.q=formspree.q||[]).push(arguments)}; | ||
| formspree('initForm', { formElement: '#contact-form', formId: 'YOUR_FORM_ID' }); | ||
| </script> | ||
| <script src="https://unpkg.com/@formspree/ajax@1/dist/global.js" defer></script> | ||
|
|
||
| In this Vite demo, global.js is loaded via a module entry that aliases to the source. | ||
| --> | ||
|
|
||
| <!-- Step 1: Load the library --> | ||
| <script type="module" src="/global-entry.ts"></script> | ||
|
|
||
| <!-- Step 2: Initialize the form --> | ||
| <script type="module"> | ||
| formspree('initForm', { | ||
| formElement: '#contact-form', | ||
| formId: 'YOUR_FORM_ID', | ||
| debug: true, | ||
| }); | ||
| </script> | ||
| </body> | ||
| </html> |
Uh oh!
There was an error while loading. Please reload this page.