Skip to content

Form

The resources/js/Components/Form directory contains Vue components that are used to create forms across the application. These components are designed to be reused throughout the application and are not tied to a specific feature.

AppCheckbox

The AppCheckbox Vue Component is a wrapper around the HTML <input> element of type checkbox and can be used as follows:

template
<div class="mt-4 flex items-center">
    <AppCheckbox
        id="term"
        v-model="isTermAccepted"
        name="term"
        :value="true"
    />
    <AppLabel for="term" class="ml-3">
        Accept Terms and Conditions
    </AppLabel>
</div>
vue
<script setup>
import { ref } from 'vue'

const isTermAccepted = ref(false)
</script>

And it will be rendered as:

Debugger info: isTermAccepted = false

The example above is suitable for a single checkbox. However, to create a list of checkboxes, you can use the AppCheckbox component within a loop and utilize the v-model directive to bind each checkbox to an array of values:

template
<div
    v-for="permission in permissions"
    :key="permission.id"
    class="mb-4 flex items-center"
>
    <AppCheckbox
        :id="permission.name"
        v-model="enabledPermissions"
        name="permission"
        :value="permission"
    />
    <AppLabel :for="permission.name" class="ml-3">
        {{ permission.name }}
    </AppLabel>
</div>
vue
<script setup>
import { ref } from 'vue'

const permissions = [
  { id: 1, name: 'permission 1' },
  { id: 2, name: 'permission 2' },
  { id: 3, name: 'permission 3' }
]

const enabledPermissions = ref([])
</script>

The rendered AppCheckbox will be:

Debugger info: enabledPermissions = []

AppCheckbox Props

NameTypeDefaultDescription
modelValue[Boolean, Array][]The value binding of the checkbox.
value[String, Number, Boolean, Object]''The value persisted when the checkbox is checked.

AppCombobox

The AppCombobox Vue Component acts as a select list, but it also allows the user to type in the input field to filter the options (received as a component property). The options are filtered by the label property of the options array, and the value property of the selected option is bound to the v-model directive.

template
<AppCombobox v-model="selectedOption" :options="options" />
vue
<script setup>
import { ref } from 'vue'

const options = [
  { value: 1, label: 'option 1' },
  { value: 2, label: 'option 2' },
  { value: 3, label: 'option 3' }
]

const selectedOption = ref(null)
</script>

The rendered AppCombobox will be:

  • option 1
  • option 2
  • option 3

Debugger info: selectedOption =

AppCombobox Props

NameTypeDefaultDescription
modelValue[Object, Number, String, null]The value binding of the checkbox.
comboLabelString'Dropdown search'The initial text showed before any search or selection.
useSearchBooleantrueEnables or disables the search feature of the component.
searchPlaceholderString'Search'The placeholder text of the search input.
optionsArray[]The array of objects containing the options to be selected by the user [{value: 1, label: 'One'}, ...]

AppFormErrors

The AppFormErrors Vue Component automatically receives the form errors from the backend and displays them in a list. Suppose you have a form with the following input fields:

  • Name (required)
  • Email (must be a valid email)

The validation of the form is handled by the backend (using Laravel with an Inertia.js response). If any validation errors are triggered, the AppFormErrors component will display the error message(s) in a list.

template
<AppFormErrors class="mb-4" />

The rendered AppFormErrors will be:

Whoops! Something went wrong...
  • The name field is required.
  • The email field must be a valid email address.

AppInputDate

The AppInputDate Vue Component is a wrapper around the HTML <input> element of type date, and can be used as follows:

template
<div class="mt-4 w-64">
    <AppInputDate
        v-model="publishedAt"
        label="Publish Date"
        name="publish_date"
    ></AppInputDate>
</div>
vue
<script setup>
import { ref } from 'vue'

const publishedAt = ref('')
</script>

The rendered AppInputDate will be:

Debugger info: publishedAt (ready for database insert as yyyy-mm-dd) =

AppInputDate Props

NameTypeDefaultDescription
modelValueString''The value binding of the input.
nameString''The name of the input.
labelString''The label of the input.

AppInputFile

The AppInputFile Vue Component acts as a wrapper for the HTML <input> element with a file type. It is primarily designed to manage image uploads, providing real-time previews, but can also be easily adapted for other file types as required. Usage is as follows:

template
<div class="mt-4">
    <AppInputFile
        v-model="image"
    ></AppInputFile>
</div>
vue
<script setup>
import { ref } from 'vue'

const image = ref('')
</script>

The rendered result will be:

Debugger info: image =

AppInputFile Props

NameTypeDefaultDescription
imagePreviewUrl[String, null]nullFor update actions, this property can be used to fill the component with a preview of an image that was uploaded earlier. It requires the complete path of the image intended for preview.
showRemoveFileButtonBooleantrueWhen set to false, this property disables the deletion of the uploaded file, in cases where the file is required and can't be deleted.

AppInputFile Events

NameArgumentsDescription
update:modelValue[File, null]Update the model value by passing a JavaScript File object, or use null when the file is removed from the AppInputFile.
removeFile[Boolean]This is used to notify the parent component when the user decides to remove a previously uploaded file. It is generally utilized in edit actions to delete a file that was uploaded during the creation of the resource (using the create method).

AppInputPassword

The AppInputPassword Vue Component is a wrapper around the HTML <input> element of type password, providing a convenient way to handle password inputs by automatically adding options to show or hide the typed password.

template
<div>
    <AppLabel for="email">Password</AppLabel>
    <AppInputPassword
        id="password"
        v-model="form.password"
        name="password"
        class="w-full"
        autocomplete="current-password"
        :class="{
            'input-error': errorsFields.includes('password')
        }"
    />
</div>
vue
<script setup>
import { useForm } from '@inertiajs/vue3'
import useFormErrors from '@/Composables/useFormErrors'

const form = useForm({
  password: ''
})

const { errorsFields } = useFormErrors()
</script>

The rendered AppInputPassword will be:

AppInputPassword Props

NameTypeDefaultDescription
modelValueString-The value binding of the input.

AppInputText

The AppInputText Vue Component is a wrapper around the HTML <input> element of type text, and can be used as follows:

template
<div>
    <AppLabel for="email">Email</AppLabel>
    <AppInputText
        id="email"
        v-model="form.email"
        type="text"
        :class="{
            'input-error': errorsFields.includes('email')
        }"
    />
</div>
vue
<script setup>
import { useForm } from '@inertiajs/vue3'
import useFormErrors from '@/Composables/useFormErrors'

const form = useForm({
  email: ''
})

const { errorsFields } = useFormErrors()
</script>

The rendered AppInputText will be:

AppInputText Props

NameTypeDefaultDescription
modelValue[String, Number]''The value binding of the input.

AppLabel

The AppLabel Vue Component is a wrapper around the HTML <label> element and can be used as follows:

template
<div>
    <AppLabel for="email">Email</AppLabel>
    <AppInputText
        id="username"
        v-model="form.username"
        type="text"
        :class="{
            'input-error': errorsFields.includes('username')
        }"
    />
</div>
vue
<script setup>
import { useForm } from '@inertiajs/vue3'
import useFormErrors from '@/Composables/useFormErrors'

const form = useForm({
  username: ''
})

const { errorsFields } = useFormErrors()
</script>

The rendered AppLabel will be:

AppLabel Slots

NameDescription
defaultThe content of the label element.

AppRadioButton

The AppRadioButton Vue Component is a wrapper around the HTML <input> element of type radio, and can be used as follows:

template
<AppRadioButton
    v-for="option in radioOptions"
    :id="option.value"
    :key="option.value"
    v-model="selectedRadioOption"
    name="myoptions"
    :value="option.value"
    class="mr-3"
>
    {{ option.label }}
</AppRadioButton>
vue
<script setup>
import { ref } from 'vue'

const radioOptions = [
  { value: 1, label: 'option 1' },
  { value: 2, label: 'option 2' },
  { value: 3, label: 'option 3' }
]

const selectedRadioOption = ref(null)
</script>

The rendered AppRadioButton will be:

Debugger info: selectedRadioOption =

AppRadioButton Props

NameTypeDefaultDescription
modelValue[String, Number, Boolean]falseThe value binding of the radio input.
value[String, Number, Boolean]falseThe value persisted when the radio is checked.

AppTextArea

The AppTextArea Vue Component is a wrapper around the HTML <textarea> element and can be used as follows:

template
<AppLabel for="notes">Notes</AppLabel>
<AppTextArea
    id="notes"
    v-model="form.notes"
    class="h-24"
    :class="{
        'input-error': errorsFields.includes('notes')
    }"
/>
vue
<script setup>
import { useForm } from '@inertiajs/vue3'
import useFormErrors from '@/Composables/useFormErrors'

const form = useForm({
  notes: ''
})

const { errorsFields } = useFormErrors()
</script>

The rendered AppTextArea will be:

AppTextArea Props

NameTypeDefaultDescription
modelValueString-The value binding of the textarea element.
autoResizeBooleantrueIf true, textarea will grow instead of displaying a scrollbar.

AppTipTapEditor

The AppTipTapEditor Vue Component is a reusable Rich Text Editor. It's a wrapper around the excellent Tiptap Editor, and includes a variety of custom-made customizations and extensions to make it work seamlessly with your Modular Laravel Application. Some custom features of the Modular version of the Tiptap Editor include:

  • Full Theme Integration - It is fully integrated with your Modular Theme, ensuring it automatically inherits the visual aspects of your application with consistency.

  • Translation Support - For an enhanced user experience, tooltips are displayed when you mouse over the editor buttons, showing the translated action for each button. The translation system is managed in your backend and extends to your frontend, including the Editor Toolbar.

  • Image Upload - This version has been extended with image upload functionality. Backend integration is handled by a PHP Trait in your Laravel Controller, providing a ready-to-use pattern with minimal effort.

  • Code Mode - A Code Mode is available, allowing you to write or edit the HTML code generated by the editor.

The AppTipTapEditor Vue Component can be used as follows:

template
<div class="mt-4">
    <AppLabel for="notes">Notes</AppLabel>
    <AppTipTapEditor
        v-model="form.notes"
        :class="{
            'app-tip-tap-error': errorsFields.includes('notes')
        }"
        :file-upload-url="route('customer.uploadEditorImage')"
    />
</div>
vue
<script setup>
import { useForm } from '@inertiajs/vue3'
import useFormErrors from '@/Composables/useFormErrors'

const form = useForm({
  notes: ''
})

const { errorsFields } = useFormErrors()
</script>

The rendered AppTipTapEditor will be:

Image Upload

The Modular Version of the Tiptap Editor is extendend with an image upload functionality. The image upload, triggered by the Add Image Button (that has the icon ) in the Editor Toolbar, is handled by the backend using a PHP Trait in your Laravel Controller. This allows for easy reuse in any controller you wish. Within your AppTipTapEditor component, you can pass the route to the image upload action of your Laravel Controller using the file-upload-url prop:

template
<div class="mt-4">
    <AppLabel for="notes">Notes</AppLabel>
    <AppTipTapEditor
        v-model="form.notes"
        :class="{
            'app-tip-tap-error': errorsFields.includes('notes')
        }"
        :file-upload-url="route('customer.uploadEditorImage')"
    />
</div>

Note that the route() method is available in all your Modular Vue Templates, provided by the Ziggy composer package, which is automatically integrated into your Modular Application. There's no extra setup required for it to work. Just define your routes in your Laravel Module, and you can utilize them in your Vue Templates.

modules/Customer/routes/app.php file:

php
<?php

use Illuminate\Support\Facades\Route;

Route::post('customer/upload-editor-image', [
    'uses' => 'CustomerController@uploadEditorImage',
])->name('customer.uploadEditorImage');

modules/Customer/Http/Controllers/CustomerController.php file:

php
<?php

namespace Modules\Customer\Http\Controllers;

use Modules\Support\Http\Controllers\BackendController;
use Modules\Support\Traits\EditorImage;

class CustomerController extends BackendController
{
    use EditorImage;
}

That's it! The EditorImage trait includes the uploadEditorImage() method (utilized in your upload route), which manages the image upload process and returns the image parameters back to the AppTipTapEditor:

  • fileName
  • filePath
  • fileUrl
  • readableName

By default, files are uploaded to the storage/app/public/editor-files directory. However, you can customize this location by setting the uploadImagePath property in your Controller.

php
<?php

namespace Modules\Customer\Http\Controllers;

use Modules\Support\Http\Controllers\BackendController;
use Modules\Support\Traits\EditorImage;

class CustomerController extends BackendController
{
    use EditorImage;

    protected string $uploadImagePath = 'storage/app/public/user-files';
}

Video Embed

To embed a video in your editor, you can use the Add Video Button (that has the icon ) in the Editor Toolbar. This action opens a modal window where you can paste the URL of the video. The embed code will then be inserted into your editor and rendered as a video in the frontend.

Code Mode

The Modular version of the Tiptap Editor provides a Code Mode, which allows you to write or edit the HTML code generated by the editor. To enable the Code Mode, use the Code View Button (that has the icon ) in the Editor Toolbar. This action will replace the editor content with the editor's generated HTML code for editing. To revert to the normal editor mode, simply click the Code View Button again to toggle off the Code Mode.

AppTipTapEditor Props

NameTypeDefaultDescription
modelValueString''The value binding of the editor.
editorClassString''Css classes to be added to the Editor instance.
fileUploadUrl[String, Boolean]falseThis property should be set to the URL path of the backend endpoint that will handle file upload requests (e.g., '/customer/uploads'). If this property is false, the file upload functionality will be disabled.
allowedFileTypesString'image/*'Comma separated list of the allowed file types for upload.