Larastrap Recipes

Reusable Bootstrap5 components for Laravel

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.

Share your Larastrap Recipes!


A simple x-larastrap::text input can be decorated with a Bootstrap icon and marked with the .date CSS class, used to attach Bootstrap Datepicker (or whatever datepicker JS library you prefer) initialization.
Using reviewCallback it is possible to format the value before display.

Configuration

[
    '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;
                }
            ],
        ],
    ]
]

Code

<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-wbDVT5mZyR" class="col-2 col-form-label">Pick a Date</label>
  <div class="col-10">
    <div class="input-group">
      <input id="input-wbDVT5mZyR" type="text" class="date form-control" name="" value="Wednesday 08 December 2021" 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>
It may be useful to append an icon by default to a x-larastrap::button with a specific intent, such as open a x-larastrap::modal window.

Configuration

[
    'customs' => [
        'mbutton' => [
            'extends' => 'button',
            'params' => [
                'color' => 'light',
                'postlabel' => ' <i class="bi-window"></i>',
            ],
        ],
    ]
]

Code

<x-larastrap::mbutton label="Open Modal" triggers_modal="#test-modal" />

<x-larastrap::modal title="Test" id="test-modal">
  <p>Ciao</p>
</x-larastrap::modal>
<button id="button-ByuNt14F0p" class="btn btn-light" data-bs-toggle="modal" data-bs-target="#test-modal">Open Modal</button>
<div class="modal fade" id="test-modal" tabindex="-1" aria-hidden="true">
  <div class="modal-dialog modal-none">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title">
          Test
        </h5>
      </div>
      <div class="modal-body">
        <p>
          Ciao
        </p>
      </div>
      <div class="modal-footer">
        <button id="button-O6EmRFZTzD" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
      </div>
    </div>
  </div>
</div>
What about injecting your Laravel Dusk selectors only when actually running Dusk tests? This can be in particular useful with x-larastrap::checks and x-larastrap::radios, and be able to select with precision your options and test your own combinations.

Configuration

[
    '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;
                }
            ],
        ],
    ]
]

Code

<x-larastrap::testablechecks name="choose" label="Choose one" :options="['1' => 'one', '2' => 'two', '3' => 'three']" />
<div class="row mb-3">
  <label for="checks-qH8yGV7Vph" 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-qH8yGV7Vph-4278275292391265578" autocomplete="off" value="1"> <label class="btn btn-outline-primary" for="checks-qH8yGV7Vph-4278275292391265578" dusk="choose-1">one</label> <input type="checkbox" class="btn-check" name="choose[]" id="checks-qH8yGV7Vph-5624722149045902711" autocomplete="off" value="2"> <label class="btn btn-outline-primary" for="checks-qH8yGV7Vph-5624722149045902711" dusk="choose-2">two</label> <input type="checkbox" class="btn-check" name="choose[]" id="checks-qH8yGV7Vph-3370452942331839787" autocomplete="off" value="3"> <label class="btn btn-outline-primary" for="checks-qH8yGV7Vph-3370452942331839787" dusk="choose-3">three</label>
    </div>
  </div>
</div>
To avoid to fill the templates with ugly strings such as :label="__('Translatable string')" it is possible to delegate translations to a dedicated reviewCallback (perhaps set as default for one or more native components).
In this example the native Laravel localization system is used, but of course you can adopt your preferred one.
This is a short help

Configuration

[
    '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;
                }
            ],
        ],
    ]
]

Code

<!--

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-7GByaLomvC" 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-7GByaLomvC" type="text" class="form-control" name="" value="">
    <div class="form-text">
      This is a short help
    </div>
  </div>
</div>