Skip to content

cubicforms/chemical-x-forms

Repository files navigation

Chemical X Forms

npm version npm downloads License Node.js Test Suite Nuxt

A fully type-safe, schema-driven form library that gives you superpowers.
Comes with a minimal composition API that prioritizes developer experience and form correctness.

🚧 this library is not production ready yet.

🏔️ Features

  • Compact API – Minimal yet expressive API surface with core functions like useForm, register, and handleSubmit to reduce boilerplate.
  • Abstract Schema Support – Integrates with validation libraries like Zod for type-safe schemas and automatic validation.
  • v-register Directive – One SSR-safe directive that automatically tracks everything.
  • Full State Tracking – Automatically tracks field states (value, touched, dirty status, validation errors, etc).
  • Reactive Field ErrorsfieldErrors auto-populates on validation failure and clears on success; setFieldErrorsFromApi maps server 422 envelopes onto fields for inline display.
  • TypeScript Friendly – Fully type-safe, with advanced form type inference from your schema.

🪩 Installation

Install with Nuxi:

npx nuxi module add @chemical-x/forms

That's it! You can now use Chemical X Forms in your Nuxt app ✨

Install manually:

# Using npm
npm install @chemical-x/forms

Then add the module to your nuxt.config.ts:

export default defineNuxtConfig({
  modules: ["@chemical-x/forms"],
});

🪄 Usage

Basic Example

<script setup lang="ts">
import { z } from "zod";

// Define your schema
const schema = z.object({ planet: z.string() });

// Create your form
const { getFieldState, register, key } = useForm({ schema });

// Get the state of the 'planet' field
const planetState = getFieldState("planet");
</script>

<template>
  <div>
    <h1>Planet Form</h1>

    <input
      v-register="register('planet')"
      placeholder="Enter your favorite planet"
    />

    <p>Planet field State:</p>
    <pre>{{ JSON.stringify(planetState, null, 2) }}</pre>
    <hr />
  </div>
</template>

Core API Functions

note: detailed documentation coming soon

useForm(options) – Initializes form state. schema is required; key is recommended on every form so multiple forms on a page don't share state.

v-register – Custom, SSR-safe directive for registering components with Chemical X

register(name: string) – Binds a field to form state.

handleSubmit(onSubmit, onError?) – Builds a submit handler that runs validation and dispatches to your callback. Bind it to @submit.prevent directly:

<script setup lang="ts">
const { handleSubmit } = useForm({ schema, key: 'signup' })
const onSubmit = handleSubmit(async (values) => {
  await api.post('/signup', values)
})
</script>

<template>
  <form @submit.prevent="onSubmit">...</form>
</template>

You can also call the returned handler programmatically: await onSubmit().

getValue(name: string) – Retrieves a field value.

setValue(name: string, value: any) – Updates a field programmatically.

getFieldState(name: string) – Returns field state (value, touched, errors, etc.).

fieldErrors – Reactive Record<path, ValidationError[]>. Auto-populated by handleSubmit on validation failure and cleared on success.

setFieldErrors(errors) / addFieldErrors(errors) – Replace or merge errors imperatively.

clearFieldErrors(path?) – Clear one path or every path.

setFieldErrorsFromApi(payload) – Map a server error envelope ({ error: { details: { path: [msg] } } } or a raw Record<path, string|string[]>) into ValidationError[] and populate the store. Returns the produced errors.

Per-field error display

<script setup lang="ts">
import { z } from 'zod'

const { register, fieldErrors, handleSubmit, setFieldErrorsFromApi } = useForm({
  schema: z.object({ email: z.string().email() }),
  key: 'signup',
})

const onSubmit = handleSubmit(async (values) => {
  // server-side hydration after client validation passed:
  try {
    await $fetch('/api/signup', { method: 'POST', body: values })
  } catch (err) {
    if (err.statusCode === 422) setFieldErrorsFromApi(err.data)
  }
})
</script>

<template>
  <form @submit.prevent="onSubmit">
    <input v-register="register('email')" />
    <small v-if="fieldErrors.email?.[0]">{{ fieldErrors.email[0].message }}</small>
    <button>Submit</button>
  </form>
</template>

🥇 Advanced Features

  • Fully SSR Safe – Fully Nuxt 3-compatible with hydration-safe bindings.

  • Validation Handling – Displays schema validation errors automatically.

  • Performance Optimizations – Efficient reactive updates for optimal performance.


🪪 License

@chemical-x/forms is released under the MIT License. See the LICENSE file for details.

About

A fully type-safe, schema-driven form library that gives you superpowers. Chemical X included.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors