Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Forms Laravel Package

rinvex/laravel-forms

Rinvex Laravel Forms is a database-driven form builder for Laravel, letting you define forms and fields dynamically, render them in views, and manage submissions without hardcoding HTML. It supports validation, customizable field types, and flexible storage.

View on GitHub
Deep Wiki
Context7

Getting Started

Reality check first. This package is archived and marked abandoned. Before you invest a day in it, decide whether you are comfortable owning the code: fork it, pin the exact commit, and verify it installs against your Laravel/PHP version. If you are on Laravel 10+, expect dependency conflicts and plan to either patch composer.json constraints in a fork or use --ignore-platform-reqs only as a temporary diagnostic, never as a production strategy.

Minimal install:

composer require rinvex/laravel-forms
php artisan vendor:publish --provider="Rinvex\Forms\Providers\FormsServiceProvider"
php artisan migrate

Where to look first, in this order:

  1. config/rinvex.forms.php — model bindings, table names, route prefix/middleware, field-type mappings. This is the main extension surface.
  2. database/migrations/* — the forms and form-field tables. Read the columns before writing any model code; the package is thin and the schema is the real API.
  3. src/Models/Form.php and src/Models/Field.php — relationships, accessors, and any render()/toArray() helpers.
  4. Published views under resources/views/vendor/rinvex/forms — this is where field markup lives and where you will almost certainly need to make changes.

A realistic first use case is a database-driven contact form. Define it once in a seeder so it is version-controlled:

use Rinvex\Forms\Models\Form;

$form = Form::create([
    'name'   => 'Contact Us',
    'slug'   => 'contact-us',
    'method' => 'POST',
    'action' => route('contact.submit'),
]);

$form->fields()->createMany([
    ['name' => 'name',    'type' => 'text',     'label' => 'Name',    'validation' => 'required|string|max:255', 'sort' => 1],
    ['name' => 'email',   'type' => 'email',    'label' => 'Email',   'validation' => 'required|email',          'sort' => 2],
    ['name' => 'message', 'type' => 'textarea', 'label' => 'Message', 'validation' => 'required|string',         'sort' => 3],
]);

Then in a controller:

$form = Form::where('slug', 'contact-us')->firstOrFail();
return view('contact', compact('form'));

And in Blade, either use the package renderer if it suits your markup:

{!! $form->render() !!}

…or, more likely for day-to-day work, render the fields yourself so you control escaping and CSS:

<form method="{{ $form->method }}" action="{{ $form->action }}">
    @csrf
    @foreach ($form->fields->sortBy('sort') as $field)
        <div class="form-group">
            <label for="{{ $field->name }}">{{ $field->label }}</label>
            @include("forms.fields.{$field->type}", ['field' => $field])
        </div>
    @endforeach
    <button type="submit">Send</button>
</form>

Implementation Patterns

Treat the package as a schema + renderer, not a full form framework. The durable pattern is: store form definitions in the database, render them through your own Blade partials, and own submission handling in application code. That keeps you insulated if you later replace the package.

Seeder-driven definitions for fixed forms. For forms that are part of the product (contact, application, survey), define them in seeders or migrations rather than through an admin UI. Use updateOrCreate keyed on slug so re-seeding is idempotent and field changes are reviewable in git.

Dynamic validation from field metadata. The most useful integration point is mapping stored validation strings onto Laravel’s validator:

$rules = $form->fields->mapWithKeys(function ($field) {
    return [$field->name => $field->validation ?: 'nullable'];
})->all();

$data = $request->validate($rules);

If validation strings can be edited at runtime, parse them defensively (strip unknown rules, whitelist rule names) rather than passing arbitrary strings into the validator.

Field partials per type. Create resources/views/forms/fields/{text,email,textarea,select,checkbox,radio}.blade.php and keep each partial responsible for one input. This is the cleanest extension point: a new field type is a new partial plus a config entry, not a package fork.

Frontend/API integration. If you render with Vue, React, or Livewire, don’t use the package’s HTML renderer at all. Serialize definitions instead:

return response()->json([
    'form'   => $form->only(['name', 'slug', 'method', 'action']),
    'fields' => $form->fields->map->only(['name', 'type', 'label', 'options', 'validation', 'sort']),
]);

The frontend renders controls; the backend still validates with the same rules. This is usually a better fit than server-rendered markup for anything interactive.

Submission persistence is yours. Unless you have verified otherwise in the source, assume the package does not provide a robust submissions table or spam handling. Create a form_submissions table with form_id, payload JSON, ip, and timestamps, and store $data there after validation. Add honeypot/rate-limiting at the controller level.

Admin CRUD. If you need non-developers to edit forms, build a small resource controller around Form and Field. Use nested resources (forms.fields) and a sortable list. Wrap edits in a transaction when reordering fields.

Testing. Write feature tests that post to your submission endpoint and assert both validation failures and successful persistence. Seed a form in the test and assert that every field name in the definition appears in the rendered HTML. This catches field/type mismatches early.

Gotchas and Tips

  • Abandonment is the dominant risk. There will be no fixes for Laravel upgrades, security issues, or PHP 8.2+ deprecations. Fork early, rename the namespace if necessary, and keep the fork in your own VCS. Don’t let it become an unowned dependency.
  • Read the source, not the README. Documentation is sparse and the archived README may describe an older API. Confirm method names such as render() and relationship names against src/ before building on them.
  • Rendering raw HTML is an XSS footgun. {!! $form->render() !!} is only safe if every label, placeholder, and option value is trusted. If form definitions are editable by users, escape labels in your own partials and never interpolate unescaped field attributes.
  • Field names must be unique per form. Add a unique index on (form_id, name) or validate in the admin layer. Duplicate names silently break validation because later rules overwrite earlier ones.
  • Ordering is fragile. Don’t rely on insertion order. Always sort by an explicit sort/order column, and renumber on reorder rather than using sparse values.
  • Mass assignment surprises. Check $fillable/$guarded on the package models before create() calls. If slug or action is guarded, your seeder will silently drop it.
  • Migration collisions. The published migrations may conflict with existing tables or use older schema syntax. Review them before running migrate in a shared database, and consider copying the schema into your own migrations if you need to modify it.
  • JSON/options columns. Select and radio options may be stored as JSON or serialized arrays depending on the version. Normalize on read (is_array($field->options) ? ... : json_decode(...)) rather than assuming one format.
  • Config caching. If you swap models or views via config, run php artisan config:clear after changes. Stale config is a common cause of “my custom model isn’t used” confusion.
  • Debugging tips. Start with dd($form->toArray()) and dd($form->fields->toArray()) to confirm what the package actually loaded. If rendering fails, check whether views were published and whether the view namespace matches the config. Enable query logging to confirm the fields relationship is eager-loaded; N+1 queries on forms with many fields are easy to introduce.
  • Extension points worth using: config-level model swapping (subclass Form/Field), published views for markup, and your own field partials. Avoid editing vendor/ directly; every change there is lost on the next composer update.
  • Have an exit plan. Because the form definition is just data, migrating away later means writing a new renderer and reusing the same tables. Keep your submission logic and validation decoupled from package internals so that exit is a day’s work, not a rewrite.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle