artisanpack-ui/forms
ArtisanPack UI Forms provides Laravel form components and helpers for building consistent, accessible forms with Blade. It streamlines form rendering, validation display, and styling so you can create maintainable interfaces faster.
ArtisanPack-UI Forms ships a Laravel backend (form definitions, validation, submissions) plus React and Vue FormRenderer components intended for Inertia or a Vite-mounted front end.
composer require artisanpack-ui/forms, then npm install @artisanpack-ui/forms (React or Vue entry point).php artisan vendor:publish --tag=artisanpack-forms-config and --tag=artisanpack-forms-migrations, then php artisan migrate.resources/js/Pages in the package's stubs/examples — that's the contract between backend definitions and the FormRenderer props.<FormRenderer :form="form" />. As of v1.5.2 you can get a one-line newsletter layout with no CSS by passing layout="inline" and your own button class via submitClassName.Newsletter / single-field inline forms. The headline feature in v1.5.2. Instead of a stacked email field with a button underneath, use:
<FormRenderer form={form} layout="inline" submitClassName="wp-element-button" />
The submit button becomes the last item in the field row, bottom-aligned and non-growing, and full-width fields collapse to a 12rem minimum so the button shares the line. This removes the usual flexbox overrides you'd otherwise write in a page component.
Design-system bridging via submitClassName. Both layouts append this prop to the button's classes, so a host app can pass its own token (wp-element-button, a Tailwind component class, a BEM class) and keep the package's internal button styling intact. Prefer this over global CSS targeting the submit button.
Stacked forms (default) stay the safe baseline. Multi-field forms, address blocks, and anything with textareas should keep layout="stacked". The default output is byte-for-byte unchanged in v1.5.2, so existing pages need no edits.
Per-field layout awareness. FieldRenderer now accepts the same layout prop, and the TypeScript definitions export a FormLayout type. If you build custom field wrappers or a field-rendering slot, thread layout through from FormRenderer rather than hardcoding widths, so your custom fields participate in the inline row correctly.
Multi-step wizards. Keep using the package's step machinery; the renderer ignores layout for multi-step forms, so passing it is harmless but has no effect. Style step navigation with submitClassName only for the final submit.
Integration tip. Because inline shrinks full-width fields to a 12rem minimum capped at row width, don't set an explicit narrow max-width on the field wrapper — let the row drive it and the button wrap naturally on small viewports.
inline is not a general layout mode. It is designed for one-or-two-field rows (newsletter, search, coupon). Multi-field forms will look cramped and the button will wrap awkwardly. Multi-step forms ignore it entirely.<div> in inline mode. Any host CSS or JS selector like .form-row > div:last-child button will silently miss. Target the button by class or by submitClassName instead.submitClassName is appended, not replacing. Internal button classes remain, so design-system resets that rely on being the only class may need !important or a wrapper scope.FormLayout from the package's type entry point; older local type shims declaring FieldRenderer props will now conflict. Re-run your type check after upgrading.submitClassName isn't present, the prop isn't reaching FormRenderer (common with Inertia partial reloads or a stale Vue/React build). Clear the Vite build cache before chasing CSS.How can I help you explore Laravel packages today?