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

Forms Laravel Package

grafite/forms

Grafite Forms is a Laravel package for building and managing dynamic forms. It provides a simple API for defining fields, rendering forms, validating input, and handling submissions, making it easy to add configurable, database-backed forms to your application.

View on GitHub
Deep Wiki
Context7

Getting Started

Install via Composer and publish the package assets:

composer require grafite/forms
php artisan vendor:publish --provider="Grafite\Forms\FormsServiceProvider"

This drops a config/forms.php (theme, wrapper classes, field defaults) and the Blade partials the renderer uses. Read config/forms.php first — it tells you what markup the package will emit and where you can swap templates. As of v6.0.0 the default theme targets Bootstrap 5, so if your app is on Bootstrap 4, Tailwind, or no CSS framework at all, that decision is made in config/views before you write a single form class.

Then generate or hand-write a form class that extends Grafite\Forms\Forms\Form:

namespace App\Forms;

use Grafite\Forms\Forms\Form;

class ContactForm extends Form
{
    public $fields = 'name:text, email:email, message:textarea';
    public $actions = 'submit';
}

Render it in Blade with the facade or by echoing the instance:

{!! Form::open(ContactForm::class) !!}

The first real use case is a CRUD form bound to an Eloquent model: pass the model into the form and the package pre-fills values, wires the PUT/PATCH method spoof, and posts back to the conventional route. That's where the "magic" pays off — you stop hand-writing old() / $model->field ternaries.

Implementation Patterns

One form class per resource. PostForm, UserForm, SettingsForm — keep them declarative and free of query logic. Everything about what the form contains lives in the class; everything about who and when lives in the controller.

Model binding for edit screens. Instantiate the form with the model (or via Form::make(PostForm::class, $post)). The package maps field names to model attributes, so title:text becomes <input value="{{ $post->title }}"> and the form auto-selects PUT when the model exists. New records get the POST branch for free.

Validate outside the form. Use a Laravel FormRequest and $request->validated() before you persist. The package renders fields, not rules; trying to bolt validation into the form class couples your HTTP concern to presentation and makes testing harder. On redirect-back-with-errors, ensure the theme partial prints @error($field) — check the published view if errors aren't showing. With the Bootstrap 5 theme this should map onto is-invalid + .invalid-feedback, but confirm it in the published partials rather than assuming.

Fluent per-field tweaks beat rewriting the field string. Keep the class-level $fields as the skeleton, then adjust individual fields for classes, placeholders, or options:

$form->field('email')->setAttribute('placeholder', '[email protected]');
$form->field('role')->options(Role::pluck('name', 'id'));

Actions and buttons are configured on the form ($actions), so cancel links and extra submits stay consistent across the app. Build a small base form class with your default actions and theme, and extend it everywhere.

File uploads need the form flagged as multipart and enctype emitted by the theme — confirm it in config/forms.php, then handle storage in the controller like any other uploaded file.

Theming (Bootstrap 5 in v6). Override the package partials rather than editing vendor files. Publish views, keep your own copies under resources/views/vendor/..., and adjust wrapper classes there; the form classes stay untouched when design changes. Bootstrap 5 dropped .form-group and .form-row in favour of spacing utilities (mb-3, row g-3), renamed .form-text helpers, and moved custom controls to .form-check / .form-select — so any BS4-era overrides you carry forward need a pass, not a copy-paste.

Mixed CSS stacks. If your app is Tailwind-first and you only want Bootstrap on admin screens, treat the theme as a per-form concern: publish a second partial set and select the theme on the form class (or a base class) rather than globally rewriting config/forms.php. That keeps the v6 BS5 defaults usable without forcing Bootstrap on your whole frontend.

Gotchas and Tips

  • v6.0.0 is a major bump. The headline change is Bootstrap 5 compatibility, and the release notes stop at "and more." Treat ^6.0 as an upgrade with an unknown blast radius: read the actual CHANGELOG/diff for config keys, renamed partials, and removed methods before bumping in a real app. Pin ^5 if you're not ready to re-do markup.
  • Published views shadow package views. After upgrading, your old resources/views/vendor/... copies still win — you will not see Bootstrap 5 markup until you re-publish and diff them. This is the number-one cause of "the upgrade did nothing." Publish to a temp path or back up the directory, re-publish, then merge by hand.
  • Theming regression surface. Anything you previously patched around .form-group wrappers, invalid states, checkbox/radio markup, or select rendering is the most likely thing to break. Snapshot the rendered markup before and after the upgrade and diff it — that's your regression test.
  • The field DSL is a string parser. Commas and colons are delimiters, so labels containing them get mangled. If you need rich labels or custom attributes, use the fluent field() API or define fields as an array rather than fighting the string.
  • Output is raw. Forms render via {!! !!}; never interpolate user-supplied labels or option text directly into the field DSL. Escape labels in the controller or use the fluent setters.
  • Config and view caching. After editing config/forms.php run php artisan config:clear; after re-publishing views run php artisan view:clear. A stale cache is the usual cause of "my theme change did nothing" — and during a v6 upgrade you'll likely hit both at once.
  • Debugging the markup is easiest by dumping the rendered string in a test ($form->render()) and asserting on it — faster than clicking through a browser and grepping the DOM. Do this before the upgrade, so you have a baseline to compare against.
  • Maintenance posture has changed. v6 signals the package is alive again after a long quiet period, which is good news for the illuminate/* constraints — but a single recent release is still thinner ground than a steady cadence. Check the constraints against your Laravel version, and keep the form classes as plain objects you can render and test yourself so a future stall is survivable.
  • Extension point: the form class is just a plain object. Subclass it, add helper methods (->forAdmin() toggling fields), and write unit tests against the produced HTML. That's the cheapest way to keep the package's magic from becoming unexplainable behaviour six months from now — and the cheapest way to validate a major upgrade.
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.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
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