Download the PHP package roro/roroform without Composer

On this page you can find all versions of the php package roro/roroform. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package roroform

RoroForm

Build full Laravel forms out of Blade components — and drive every field from JavaScript like it's 2026.

25+ input components · searchable selects · repeatable groups that actually work · a chainable, type-aware JS API · fully responsive & accessible · Tailwind, Bootstrap & framework-free themes — wired into Laravel's old(), validation errors and CSRF out of the box.

▶ Live playground · Quick start · Docs

tests 870 tests passing Zero JS dependencies PHP ^8.0 Laravel 9 to 13 Tailwind | Bootstrap | none Apache-2.0


Why RoroForm?

Most Laravel form helpers stop at rendering an <input>. RoroForm goes the whole way — from the Blade tag to the runtime behaviour in the browser.


RoroForm vs. the alternatives

If you've shopped for Laravel form tooling, you've met the usual options. Here's where RoroForm sits:

Feature RoroForm Collective / Spatie helpers Filament / Livewire
Nested repeatable groups (selects & files inside) ✅ just works ❌ ⚠️ heavy stack
Runtime JS API to drive fields ✅ chainable, type-aware ❌ ⚠️ partial
JS dependencies none varies full framework
Works in plain Blade / any stack ✅ ✅ ❌ tied to their runtime
Zero-CSS-framework option ✅ raw theme ❌ ❌
Searchable, accessible custom selects ✅ ARIA combobox ❌ ✅

Laravel Collective's Form/Html package is archived; Filament and Livewire are excellent, but they pull in a full reactive runtime. RoroForm aims at the middle: server-rendered Blade with a real JS layer, no framework lock-in.


Quick start

Requirements: PHP ^8.0 · Laravel 9 → 13. CSS is optional — the raw theme (framework-free) ships its own stylesheet, so you only need Tailwind or Bootstrap if you pick that theme. No JavaScript dependencies — the runtime is vanilla JS.

1. Install

2. Publish the config (optional but recommended)

This creates config/roroform.php:

3. Drop a form in any Blade view — no scripts to add:

That's it. Label, validation, error display, CSRF and the AJAX submit are all handled — and the assets are injected automatically. No <script src>, no @vite, nothing else to add.


A real form in 30 seconds

A taste of the breadth — every field below is a single tag:


📚 Documentation

Everything below is collapsed to keep this page scannable. Open the part you need.

🧱 The component catalog — every input type
Every component renders a full field: wrapper, optional label, the control, a validation border and an error slot — all themed. Names map onto Laravel's request payload exactly as you'd expect, including nested array names like `user[26][name]`. | Component | Renders | Notable props | |-----------|---------|---------------| | `` | `` | `value` `placeholder` `required` `disabled` `readonly` | | `` `` `` `` | typed text inputs | same as text | | `` | `` | `min` `max` `step` | | `` | `` | `value` | | `` `` `` `` `` | native date/time pickers | `value` | | `` | slider | `min` `max` `step` `list` | | `` | colour picker | `hide-text-input` | | `` | checkbox | `label` `position` (`left`/`right`) | | `` + `` | a radio group | `subtitle`; radios wrap responsively | | `` | searchable single select | `:options` `value` | | `` | searchable multi-select with tags | `:options` `:values` (name ends with `[]`) | | `` | styled file input | `:multiple` `requirements-text` | | `` | repeatable group of any of the above | see its section below | | `` | submit button | `:ajax` `form-id` `:ajax-errors` | | `` | the `
` + asset injection + overlay | `action` `method` `:multipart` `enctype` `:overlay` | **Shared field props** (from `InputMain`): `id` · `name` · `label` · `value` · `placeholder` · `:required` · `:disabled` · `:readonly` · `:hidden` · `class` · `wrapperClass` · `labelClass` · `tooltip` · `:enableError` · `:hasTopMargins` · `:populate` · `:disableJsValidation`.
🧾 Every attribute, every component — the full reference
**Conventions.** Write string attributes plainly (`label="Email"`); add a **`:` prefix** to bind booleans, numbers, arrays and PHP expressions (`:required="true"`, `:options="[...]"`). camelCase props are written in **kebab-case** in Blade — `wrapperClass` → `wrapper-class`, `hasTopMargins` → `:has-top-margins`, `requirementsText` → `requirements-text`. Any attribute *not* listed below lands on the underlying element as a plain HTML attribute (see *Arbitrary HTML attributes pass-through*). #### Shared — every field input (from `InputMain`) Applies to **all** field components below (text, number, date, select, file, checkbox, radio, repeatable…) unless noted. | Attribute | Type | Default | Description | |-----------|------|---------|-------------| | `id` | `string` | auto (`uniqid()`) | Element id; auto-generated when omitted. | | `name` | `string` | `''` | Field name — maps onto the request payload (supports nested `user[26][name]`). | | `label` | `string` | `null` | Label text rendered above/beside the control. | | `value` | `string` | `''` | Initial value (overridden by `old()` after a failed validation). | | `placeholder` | `string` | `''` | Placeholder text. | | `:required` | `bool` | `false` | Adds `required` + `aria-required`. | | `:disabled` | `bool` | `false` | Disables the control. | | `:readonly` | `bool` | `false` | Marks the control read-only. | | `:hidden` | `bool` | `false` | Renders the field's wrapper hidden (`display:none`). | | `class` | `string` | `''` | Extra classes on the **control** (merged with the `roro-*` classes). | | `wrapper-class` | `string` | `''` | Extra classes on the field **wrapper**. | | `label-class` | `string` | `''` | Extra classes on the **label**. | | `tooltip` | `string` | `null` | Tooltip text shown next to the label. | | `:enable-error` | `bool` | `true` | Render the inline error slot for this field. | | `:has-top-margins` | `bool` | `true` | Apply the default top margin to the field. | | `:populate` | `array` | `[]` | Candidate values for repopulation (first truthy wins; `old()` takes precedence). | | `:disable-js-validation` | `bool` | config | Drop the HTML validation attributes for this field. Defaults to the inverse of `defaultJsValidation`. | #### Text-like — `` `` `` `` `` `` No extra attributes — **shared only**. They differ purely by their HTML `type` (`text`/`email`/`password`/`url`/`tel`/`hidden`). #### Numeric & date/time — `` `` `` `` `` `` `` (from `NumericMain`) Shared **plus**: | Attribute | Type | Default | Description | |-----------|------|---------|-------------| | `min` | `string` | `null` | Minimum value (a number, or a date/time bound for the date inputs). | | `max` | `string` | `null` | Maximum value. | | `step` | `string` | `null` | Step increment. | | `list` | `string` | `null` | Id of a `` to attach (handy on `range`). | #### Color — `` Shared **plus**: | Attribute | Type | Default | Description | |-----------|------|---------|-------------| | `:hide-text-input` | `bool` | `false` | Hide the hex text field, leaving just the colour swatch. | #### Checkbox — `` (from `CheckableMain`) Shared (with `value` defaulting to `'1'`) **plus**: | Attribute | Type | Default | Description | |-----------|------|---------|-------------| | `:checked` | `bool` | `false` | Whether the box is checked (auto-set to `true` when a non-empty value is repopulated). | #### Radio group — `` + `` `` wraps the group in a `
`/``; each `` is one option (it's a `CheckableMain`, so its `value` is the option value and `:checked` flags the default). **``** — shared **plus**: | Attribute | Type | Default | Description | |-----------|------|---------|-------------| | `subtitle` | `string` | `null` | Helper text shown under the group legend. | | `subtitle-class` | `string` | `''` | Extra classes on the subtitle. | | `fieldset-class` | `string` | `''` | Extra classes on the `
`. | **``** — shared (with `value` = the option value) **plus** `:checked` (`bool`, `false`). #### Selects — `` `` (from `SelectableMain`) Shared **plus** (for the multi-select, end the `name` with `[]`): | Attribute | Type | Default | Description | |-----------|------|---------|-------------| | `:options` | `array` | `[]` | Options — flat `['fr' => 'France']` or grouped `['Europe' => ['fr' => 'France']]`. | | `:values` | `array` | `[]` | Pre-selected values (multi-select; single-select uses `value`). | | `:search-bar` | `bool` | `true` | Show the in-dropdown search field. | | `:clear-button` | `bool` | `true` | Show the clear (✕) button. | | `:options-open` | `bool` | `false` | Render with the dropdown initially open. | #### File — `` Shared **plus**: | Attribute | Type | Default | Description | |-----------|------|---------|-------------| | `:multiple` | `bool` | `true` | Allow selecting multiple files (end the `name` with `[]`). | | `accept` | `string` | `''` | The native `accept` filter (e.g. `image/*,.pdf`). | | `max-size` | `string` | `''` | Max size hint shown to the user. | | `requirements-text` | `string` | `''` | Free-text requirements line under the control. | #### Repeatable — `` Forwards the shared field props (except `value`/`placeholder` — a repeatable holds rows, not one value) **plus**: | Attribute | Type | Default | Description | |-----------|------|---------|-------------| | `name` | `string` | `''` | Array prefix the rows submit under (e.g. `contacts`). | | `:rows` | `array` | `[]` | Initial dataset: an array of rows (maps, or scalars in token mode). | | `:min` | `int` | `1` | Minimum number of rows (can't remove below it). | | `:max` | `int` | `null` | Maximum number of rows (`null` = unlimited). | | `:reorder` | `bool\|string` | `false` | `false`, `true`/`'buttons'` (▲▼), `'drag'` (handle), or `'both'`. | | `item-label` | `string` | `null` | Per-row heading prefix, numbered automatically (`Contact 1`…). | | `key-field` | `string` | `null` | Inner field whose value uniquely identifies a row (e.g. `id`) — target rows by stable key. | | `add-label` | `string` | `'+ Add'` | Text/markup of the add button. | | `remove-label` | `string` | `null` | Text/markup of the per-row remove button (theme default when `null`). | | `index-token` | `string` | `''` | If set (e.g. `#`), replaces the token in inner names instead of auto-prefixing. | | `:indexed` | `bool` | `true` | Set to `false` to leave inner names **verbatim** (no `prefix[i]`/token). | | `row-class` | `string` | `''` | Extra classes applied to every row. | #### Button — `` A standalone `ComponentMain` (not an `InputMain`): | Attribute | Type | Default | Description | |-----------|------|---------|-------------| | `type` | `string` | `'submit'` | The button `type` (`submit`/`button`/`reset`). | | `id` | `string` | auto | Element id. | | `class` | `string` | `''` | Extra classes on the button. | | `form-id` | `string` | `null` | The form this button submits (required for AJAX submit). | | `button-color` | `string` | `'bg-blue-600'` | Base colour class. | | `button-hover-color` | `string` | `'bg-blue-700'` | Hover colour class. | | `button-text-color` | `string` | `'text-white'` | Text colour class. | | `:disabled` | `bool` | `false` | Disable the button. | | `:has-top-margins` | `bool` | `true` | Apply the default top margin. | | `:ajax` | `bool` | `false` | Submit the form over AJAX (FormData, overlay, events). | | `:enable-ajax-errors` | `bool` | `true` | Map a `422` response's `errors` back onto the matching fields. | #### Form — `` | Attribute | Type | Default | Description | |-----------|------|---------|-------------| | `action` | `string` | `''` | Form action URL. | | `method` | `string` | `'POST'` | HTTP method (set on the ``); `@csrf` is injected for `POST`/`PUT`/`PATCH`/`DELETE`. | | `id` | `string` | auto | Form id (used by `roro.form(id)` and the button's `form-id`). | | `class` | `string` | `''` | Extra classes on the ``. | | `:multipart` | `bool` | `false` | Shortcut for `enctype="multipart/form-data"` (for file uploads). | | `enctype` | `string` | `null` | Explicit enctype — takes precedence over `:multipart`. | | `:overlay` | `bool` | `true` | Render the loading overlay used during AJAX submits. |
🔎 Smart selects — searchable, grouped, dynamic
Options are rendered **server-side**, then read and enhanced by JS. No flash of an empty dropdown, no mandatory network round-trip — and the basic value is present even before JS runs. **Add options after load** — instantly, or from your own endpoint: Selects emit a real **`roro:change`** event — fired only on actual user/programmatic changes, never on initial population: > The legacy globals (`roroAddOption`, `roroAddOptionsAjax`, `roroDisableSelect`, …) still work unchanged — the `roro()` facade is purely additive on top of them.
⭐ Repeatable groups — the headline feature
`` repeats **whatever you nest inside it** — one field or many, of any type, including searchable selects, multi-selects and file inputs. Users add, remove and (optionally) reorder rows; everything submits as a clean array. Inner field names are **relative to the row** (`name`, `email`, `type`) — the component prefixes them automatically, so the form posts: #### Prefilling (edit forms) & validation Pass an array of rows via `:rows`. After a failed validation, the re-submitted `old()` input is restored automatically — **no extra wiring**: `required` (and any HTML constraint) on inner fields is enforced per row; the hidden blueprint is inert, so it never blocks submission. #### Flat lists of scalars For a plain list (`tags[]`), use the `index-token` (default `#`) where the index should go: Or turn indexing off entirely with `:indexed="false"` and keep your own names (`` → posts the same flat `tags` array). #### Attributes | Attribute | Default | Description | |-----------|---------|-------------| | `name` | — | Array prefix the rows submit under (e.g. `contacts`). | | `:rows` | `[]` | Initial dataset: an array of rows (objects, or scalars in token mode). | | `:min` | `1` | Minimum number of rows (can't remove below it). | | `:max` | `null` | Maximum number of rows (`null` = unlimited; *Add* disables at the cap). | | `:reorder` | `false` | Show up/down buttons to reorder rows. | | `item-label` | `null` | Per-row heading prefix, numbered automatically (`Contact 1`, `Contact 2`…). | | `key-field` | `null` | Inner field whose value uniquely identifies a row (e.g. `id`) — lets JS target a row by a **stable key** instead of position. | | `add-label` | `+ Add` | Text/markup of the add button. | | `remove-label` | `✕` | Text/markup of the per-row remove button. | | `index-token` | `''` | If set (e.g. `#`), replaces the token in inner names instead of auto-prefixing — use for flat lists or full control. | | `:indexed` | `true` | Set to `false` to leave inner names **verbatim** (no `prefix[i]`/token) — you control the naming. | | `row-class` | `''` | Extra classes applied to every row. | Selects, multi-selects and file inputs added in new rows are wired up **exactly** like on page load (regenerated ids, registered instances) — nothing extra to call.
🎛️ The roro() facade — one chainable, type-aware API
A small, **dependency-free** facade so you can drive any field without caring about its underlying markup. Everything is **chainable** and **type-aware** — the same call works on a text input, a select, a checkbox or a file field. `value()` is universal: text for inputs, the selected option for a `select`, an **array** for a multi-select, the checked state for a checkbox, the checked value for a radio group, file names for a file input. | Group | Methods | |-------|---------| | Value | `value(v?)` · `val(v?)` · `clear()` · `reset()` | | State | `disable(b=true)` · `enable()` · `readonly(b=true)` · `editable()` · `required(b=true)` · `optional()` · `isDisabled()` · `isReadonly()` · `isRequired()` | | Display | `show()` · `hide()` · `toggle(b?)` · `isVisible()` · `label(t?)` · `placeholder(t?)` | | Error | `error(msg)` · `clearError()` | | Events | `on(ev, fn)` · `off(ev, fn)` · `trigger(ev)` · `change(fn)` · `input(fn)` · `click(fn)` · `focus()` · `blur()` | | Misc | `type()` · `name()` · `exists()` · `$el()` · `$control()` · `$wrapper()` · `attr()` · `prop()` · `addClass()` / `removeClass()` / `toggleClass()` | **Select-only methods** (no-op elsewhere): `addOption` · `addOptions` · `addOptionsAjax` · `setOptions` · `removeOption` · `clearOptions` · `options` · `open` · `close`. #### Repeatables from JS Need one **specific row**? Prefer a **stable key** over a position — add `key-field="id"` to the component (with an `id` field, often hidden, per row):
📨 The roro.form() facade — drive the whole form
`fill()` matches keys against field **names** first (so it maps straight onto your server payload / `old()` data) and falls back to element **ids**. It even understands repeatable groups and custom selects, not just native inputs.
📋 Complete helper reference
Every flat `roro*(id, …)` global is a one-liner shortcut for the matching `roro(id).method(…)` call — use whichever reads better. `id` is the component's `id` (or, for forms, the form id). Below is the **full** list. #### Entry points & introspection | Helper | What it returns / does | Example | |--------|------------------------|---------| | `roro(target)` | A type-aware handle (field or form); `target` is an id or a DOM element | `roro('email').focus()` | | `roro.field(id)` | A field handle (explicit) | `roro.field('email')` | | `roro.form(id)` | A form handle | `roro.form('signup')` | | `roro.select(id)` | The underlying `RoroSelect`/`RoroMultiSelect` instance | `roro.select('country')` | | `roro.repeatable(id)` | The underlying `RoroRepeatable` instance | `roro.repeatable('contacts')` | | `roro.exists(target)` | `true` if the field/form is in the DOM | `if (roro.exists('email')) …` | | `roro.all(root?)` | Handles for every field under `root` (default: document) | `roro.all().forEach(h => h.clear())` | | `roro.ready(fn)` | Run `fn` on DOM ready | `roro.ready(() => …)` | | `roro.version` | The runtime version string | `roro.version // '2.0.0'` | | `roroGetSelect(id)` | Same as `roro.select(id)` | `roroGetSelect('country')` | | `roroGetRepeatable(id)` | Same as `roro.repeatable(id)` | `roroGetRepeatable('contacts')` | #### Field value & state | Helper | Does | Example | |--------|------|---------| | `roroValue(id, v?)` | Get (omit `v`) or set the value — type-aware | `roroValue('email', '[email protected]')` · `roroValue('email')` | | `roroClear(id)` | Clear / reset the field | `roroClear('email')` | | `roroDisable(id, b=true)` | Disable (or enable with `false`) | `roroDisable('age')` | | `roroEnable(id)` | Enable | `roroEnable('age')` | | `roroReadonly(id, b=true)` | Toggle readonly | `roroReadonly('age')` | | `roroRequired(id, b=true)` | Toggle the HTML `required` flag | `roroRequired('email')` | | `roroShow(id)` / `roroHide(id)` | Show / hide the whole field (wrapper) | `roroHide('coupon')` | | `roroToggleVisibility(id, b?)` | Toggle visibility | `roroToggleVisibility('coupon', true)` | | `roroFocus(id)` | Focus the control | `roroFocus('email')` | | `roroLabel(id, text?)` | Get or set the label text | `roroLabel('email', 'E-mail')` | | `roroField(id)` | Get the field handle | `roroField('email').value()` | #### Errors | Helper | Does | Example | |--------|------|---------| | `roroClearError(id)` | Hide the field's error | `roroClearError('email')` | | `roroShowError(id, msg, show=true)` | Show (or hide) an inline error + set `aria-invalid` | `roroShowError('email', 'Already taken')` | #### Events | Helper | Does | Example | |--------|------|---------| | `roroOnChange(id, fn)` | Run `fn(value, event)` when the field changes | `roroOnChange('country', v => …)` | | `roroTrigger(id, event='change')` | Dispatch an event on the control | `roroTrigger('email', 'input')` | | `roroTriggerChangeAll()` | Fire `change` on every field | `roroTriggerChangeAll()` | #### Selects | Helper | Does | Example | |--------|------|---------| | `roroAddOption(id, label, value, category?)` | Add one option (client-side) | `roroAddOption('c', 'France', 'fr', 'EU')` | | `roroAddOptions(id, list)` | Add a batch `[{label,value,category?}]` | `roroAddOptions('c', [{label:'Spain',value:'es'}])` | | `roroAddOptionsAjax(id, url, params?)` | Fetch options from your JSON endpoint → Promise | `roroAddOptionsAjax('c', '/api/countries', {q:'fr'})` | | `roroSetOptions(id, list)` | Replace **all** options | `roroSetOptions('c', list)` | | `roroRemoveOption(id, value)` | Remove one option | `roroRemoveOption('c', 'fr')` | | `roroClearOptions(id)` | Remove every option | `roroClearOptions('c')` | | `roroOptions(id)` | Read options `[{label,value,category}]` | `roroOptions('c')` | | `roroDisableSelect(id, b=true)` | Disable a custom select | `roroDisableSelect('c')` | | `roroReadonlySelect(id, b=true)` | Make a custom select readonly | `roroReadonlySelect('c')` | | `roroShowDropDown(id, show=true)` | Open / close the dropdown | `roroShowDropDown('c', true)` | #### Repeatables | Helper | Does | Example | |--------|------|---------| | `roroAddRow(id, data?)` | Append a row (optionally prefilled) | `roroAddRow('contacts', {name:'Ada'})` | | `roroRemoveRow(id, index)` | Remove the row at a position | `roroRemoveRow('contacts', 0)` | | `roroClearRows(id)` | Remove every row | `roroClearRows('contacts')` | | `roroRows(id)` | Read all rows as data | `roroRows('contacts')` | | `roroRowsCount(id)` | Number of rows | `roroRowsCount('contacts')` | | `roroRow(id, target)` | A single-row handle (by key or position) | `roroRow('contacts', 12)` | | `roroRowField(id, target, name)` | A field handle inside one row | `roroRowField('contacts', 12, 'email')` | | `roroLockRow(id, target, b=true)` | Lock/unlock a row's remove button | `roroLockRow('contacts', 12)` | Row handles (`roroRow(...)` / `roro('contacts').row(...)`) expose: `field(name)` · `fields()` · `value(data?)` · `key()` · `index()` · `remove()` · `lockRemoval(b?)` · `allowRemoval()` · `isRemovable()` · `disable(b?)` · `enable()` · `moveUp()` · `moveDown()`. #### Forms | Helper | Does | Example | |--------|------|---------| | `roroFormData(formId)` | Serialize the form to a plain object | `roroFormData('signup')` | | `roroFillForm(formId, data)` | Prefill fields (by name, then id) | `roroFillForm('signup', user)` | | `roroSubmit(formId)` | Submit (honours the AJAX button) | `roroSubmit('signup')` | | `roroResetForm(formId)` | Native reset + clear custom selects | `roroResetForm('signup')` | | `roroClearForm(formId)` | Clear every field | `roroClearForm('signup')` | | `roroValidateForm(formId)` | `reportValidity()` → bool | `roroValidateForm('signup')` | | `roroFormErrors(formId, errors)` | Show server-side errors `{field:[msg]}` | `roroFormErrors('signup', {email:['Taken']})` | | `roroClearFormErrors(formId)` | Clear all form errors | `roroClearFormErrors('signup')` | | `roroOnSuccess(formId, fn)` | AJAX success → `fn(response, event)` | `roroOnSuccess('signup', r => …)` | | `roroOnError(formId, fn)` | AJAX error → `fn(xhr, event)` | `roroOnError('signup', x => …)` | #### Overlay & low-level | Helper | Does | |--------|------| | `roroShowOverlay(show=true)` | Show/hide the form's loading overlay | | `roroSubmitButton(buttonId, formId)` | Programmatically run a submit button's flow | | `roroRegisterButtonOnClick(buttonId)` | Wire a `.roro-btn-submit` (done automatically on load) | | `roroGetWrapper(id)` | The field's wrapper element | | `populateFormErrors(form, errors)` · `clearFormErrors(form)` | The error helpers `roroFormErrors`/`roroClearFormErrors` wrap | | `addSelect(el)` · `addMultiSelect(el)` · `addRepeatable(el)` | Register a freshly-inserted component (done automatically) | > All of the above are plain `window.*` globals — no import, no namespace. The chainable equivalents live on `roro(id)` (see the previous two sections).
🪄 Laravel-native validation, old() & AJAX
RoroForm is wired into the framework, so the usual controller flow needs no front-end glue: - **Repopulation.** Every field reads `old()` automatically after a failed validation — including nested array names and repeatable rows. - **Error display.** Each field pulls its first message from `session('errors')` and shows it inline, with a red border on the control. - **CSRF.** `` injects `@csrf` for `POST`/`PUT`/`PATCH`/`DELETE`. - **AJAX submit.** `` posts via `FormData` (file uploads included), shows a loading overlay, and fires events: Add `:ajax-errors="true"` to the button and a `422` response's `errors` payload is mapped **straight back onto the matching fields** — no manual error handling:
🎨 Theming & publishing the views
Pick a theme once in `config/roroform.php`: Three themes ship complete, **accessible**, and component-for-component identical: | Theme | Styling | Dark mode trigger | |-------|---------|-------------------| | `tailwind` | TailwindCSS utility classes | `dark:` utilities — `.dark` class (or `prefers-color-scheme`, per your Tailwind `darkMode` config) | | `bootstrap` | Bootstrap 5 classes | `data-bs-theme="dark"` on an ancestor | | `raw` | **Framework-free** — no Tailwind, no Bootstrap. Injects its own small stylesheet automatically, so you get a clean, modern look on **any** page with **zero CSS framework**. | `.dark` class or `data-roro-theme="dark"` on an ancestor | **All three themes are fully dark-mode aware** — every component remaps colors, borders, backgrounds and contrast in dark mode. Each is driven by a class/attribute on an ancestor (usually ``), so you stay in control. To follow the OS setting, map it once: Test it on the playground — click the **Dark mode** toggle to switch. The `raw` theme is themed with CSS custom properties — override `--roro-accent`, `--roro-radius`, `--roro-border`, … to restyle it, or publish the stylesheet: Every theme is accessible: proper `
🔧 Arbitrary HTML attributes pass-through
Every input forwards **arbitrary HTML attributes** (the Blade attribute bag) onto the underlying element — no need to declare them in PHP. Great for `data-*`, `aria-*`, `autocomplete`, `maxlength`, Alpine `x-` directives, etc. renders `... data-testid="email" autocomplete="email" maxlength="120">` on the ``. Custom CSS classes go through the dedicated `class` attribute and are merged with the component's own `roro-*` classes.

Requirements

PHP ^8.0
Laravel 9, 10, 11, 12, 13
JavaScript none — the runtime is dependency-free vanilla JS
CSS Tailwind, Bootstrap, or none — the raw theme ships its own stylesheet

Installation recap

Upgrading

Coming from the 1.x (jQuery) runtime? 2.0 drops jQuery for dependency-free vanilla JS. The everyday facade is unchanged; a few front-end event/return contracts changed — see the CHANGELOG for the short migration guide.

License

Apache-2.0.


All versions of roroform with dependencies

PHP Build Version
Package Version
Requires php Version ^8.0
illuminate/support Version ^9.0 || ^10.0 || ^11.0 || ^12.0 || ^13.0
illuminate/view Version ^9.0 || ^10.0 || ^11.0 || ^12.0 || ^13.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package roro/roroform contains the following files

Loading the files please wait ...