Larastrap provides the ability to define your own custom element, just extending the existing ones and providing some configuration.
This can be paired with Javascript libraries and custom PHP functions to fine-tune the intended behaviour, and reuse across your code.
.date
CSS class, used to attach Bootstrap Datepicker (or whatever datepicker JS library you prefer) initialization.[ 'customs' => [ 'datepicker' => [ 'extends' => 'text', 'params' => [ 'classes' => ['date'], 'placeholder' => 'Never', 'textappend' => '<i class="bi-calendar"></i>', 'reviewCallback' => function($component, $params) { $params['value'] = ucwords(strftime('%A %d %B %Y', $params['value'])); return $params; } ], ], ] ]
<x-larastrap::datepicker label="Pick a Date" :value="time()" /> <!-- Inclusion of Bootstrap Datepicker CSS and JS, and initialization --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.9.0/css/bootstrap-datepicker.min.css" /> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.9.0/js/bootstrap-datepicker.min.js"></script> <script> $('input.date').datepicker({ format: 'DD dd MM yyyy', autoclose: true, clearBtn: true, }); </script>
<div class="row mb-3"> <label for="input-0436782f833927d032f04bc6b9510f28" class="col-2 col-form-label">Pick a Date</label> <div class="col-10"> <div class="input-group has-validation"> <input id="input-0436782f833927d032f04bc6b9510f28" type="text" class="date form-control" name="" value="Friday 24 March 2023" placeholder="Never"> </div> </div> </div><!-- Inclusion of Bootstrap Datepicker CSS and JS, and initialization --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.9.0/css/bootstrap-datepicker.min.css"> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.9.0/js/bootstrap-datepicker.min.js"></script> <script> $('input.date').datepicker({ format: 'DD dd MM yyyy', autoclose: true, clearBtn: true, }); </script>
[ 'customs' => [ 'mobiletab' => [ 'extends' => 'tabpane', 'params' => [ 'reviewCallback' => function($component, $params) { if (isset($params['attributes']['icon'])) { $params['label'] = sprintf('<span class="d-none d-md-inline-block me-2">%s</span><i class="%s"></i>', $params['label'], $params['attributes']['icon'] ); } return $params; } ], ], ] ]
<x-larastrap::tabs active="0" classes="mobiletabs"> <x-larastrap::mobiletab label="First" icon="bi-person"> This is the first tab </x-larastrap::mobiletab> <x-larastrap::mobiletab label="Second" icon="bi-people"> This is the second tab </x-larastrap::mobiletab> </x-larastrap::tabs>
<ul class="mobiletabs nav nav-tabs" id="tabs-417bd063924ce62f2d72fa4d908bad7f" role="tablist"> <li class="nav-item" role="presentation"> <button id="tabpane-58496b32183f0f4c4d72c89568298632-0fe79d7d9354b5e6c9a5dc7ee3ab19cb" class="nav-link active" role="tab" data-bs-toggle="tab" data-bs-target="#tabpane-58496b32183f0f4c4d72c89568298632"><span class="d-none d-md-inline-block me-2">First</span></button> </li> <li class="nav-item" role="presentation"> <button id="tabpane-542989cca285826ba20344f2686e2c7c-c3e8a1ae5882c569bc20f4bda48bbe6d" class="nav-link" role="tab" data-bs-toggle="tab" data-bs-target="#tabpane-542989cca285826ba20344f2686e2c7c"><span class="d-none d-md-inline-block me-2">Second</span></button> </li> </ul> <div class="tab-content" id="tabs-417bd063924ce62f2d72fa4d908bad7f_contents"> <div class="p-3 tab-pane fade show active" id="tabpane-58496b32183f0f4c4d72c89568298632" role="tabpanel"> This is the first tab </div> <div class="p-3 tab-pane fade" id="tabpane-542989cca285826ba20344f2686e2c7c" role="tabpanel"> This is the second tab </div> </div>
[ 'customs' => [ 'testablechecks' => [ 'extends' => 'checks', 'params' => [ 'reviewCallback' => function($component, $params) { /* Choose your method to determine if you are within a Dusk test */ if (env('DUSK_TESTING')) { $options = $params['options']; $new_options = []; foreach($options as $value => $option) { if (is_object($option)) { if (!isset($option->button_attributes)) { $option->button_attributes = []; } } else { $option = (object) [ 'label' => $option, 'button_attributes' => [], ]; } $option->button_attributes['dusk'] = sprintf('%s-%s', $params['name'], $value); $new_options[$value] = $option; } $params['options'] = $new_options; } return $params; } ], ], ] ]
<x-larastrap::testablechecks name="choose" label="Choose one" :options="['1' => 'one', '2' => 'two', '3' => 'three']" />
<div class="row mb-3"> <label for="checks-9c039f94488a48603a0bb776c6a1cea4" class="col-2 col-form-label col-2 col-form-label">Choose one</label> <div class="col-10"> <div class="btn-group" role="group"> <input type="checkbox" class="btn-check" name="choose[]" id="checks-9c039f94488a48603a0bb776c6a1cea4-f97c5d29941bfb1b2fdab0874906ab82" autocomplete="off" value="1"> <label class="btn btn-outline-primary" for="checks-9c039f94488a48603a0bb776c6a1cea4-f97c5d29941bfb1b2fdab0874906ab82" dusk="choose-1">one</label> <input type="checkbox" class="btn-check" name="choose[]" id="checks-9c039f94488a48603a0bb776c6a1cea4-b8a9f715dbb64fd5c56e7783c6820a61" autocomplete="off" value="2"> <label class="btn btn-outline-primary" for="checks-9c039f94488a48603a0bb776c6a1cea4-b8a9f715dbb64fd5c56e7783c6820a61" dusk="choose-2">two</label> <input type="checkbox" class="btn-check" name="choose[]" id="checks-9c039f94488a48603a0bb776c6a1cea4-35d6d33467aae9a2e3dccb4b6b027878" autocomplete="off" value="3"> <label class="btn btn-outline-primary" for="checks-9c039f94488a48603a0bb776c6a1cea4-35d6d33467aae9a2e3dccb4b6b027878" dusk="choose-3">three</label> </div> </div> </div>
:label="__('Translatable string')"
it is possible to delegate translations to a dedicated reviewCallback (perhaps set as default for one or more native components).[ 'customs' => [ 'translatable' => [ 'extends' => 'text', 'params' => [ 'reviewCallback' => function($component, $params) { $translatable = ['label', 'help', 'pophelp']; foreach($translatable as $trans) { if (isset($params[$trans]) && !empty($params[$trans])) { $params[$trans] = __($params[$trans]); /* Do not forget that certain attributes belong to the x-larastrap::field wrapping the input component, and have also to be modified */ if (isset($params['field_params'][$trans])) { $params['field_params'][$trans] = __($params[$trans]); } } } return $params; } ], ], ] ]
<!-- In resources/lang/en/example.php file: return [ 'label' => 'This is a label', 'help' => 'This is a short help', 'pophelp' => 'This is a pophelp example text', ]; --> <x-larastrap::translatable label="example.label" help="example.help" pophelp="example.pophelp" />
<div class="row mb-3"> <label for="input-25d68b410520e2393d93f990ce154397" class="col-2 col-form-label">This is a label <span class="badge rounded-pill bg-primary" data-bs-toggle="popover" data-bs-trigger="hover" data-bs-content="This is a pophelp example text">?</span></label> <div class="col-10"> <input id="input-25d68b410520e2393d93f990ce154397" type="text" class="form-control" name="" value=""> <div class="form-text"> This is a short help </div> </div> </div>
[ 'customs' => [ 'username' => [ 'extends' => 'text', 'params' => [ 'attributes' => [ 'autocomplete' => 'off', 'autocorrect' => 'off', 'autocapitalize' => 'none', 'spellcheck' => 'false', ] ], ], ] ]
<x-larastrap::username label="Username" name="username" />
<div class="row mb-3"> <label for="input-42fd05eb565c1a5946e1bbdbe05ffbc1" class="col-2 col-form-label">Username</label> <div class="col-10"> <input id="input-42fd05eb565c1a5946e1bbdbe05ffbc1" type="text" class="form-control" name="username" value="" autocomplete="off" autocorrect="off" autocapitalize="none" spellcheck="false"> </div> </div>