New version 1.30.0 is now available 🎉 Introducing a useful command to search for component usage.

Powerful suite of Blade components for TALL Stack apps.

Soft Personalization

The soft personalization.

Soft personalization consists of personalize components at run time, through a service provider, such as AppServiceProvider . The idea behind soft personalization is to tap into personalizable blocks of each component. Even if you are just starting to work with Laravel and Livewire, with a little attention to the documents below you will be able to customize the components using this concept.

Example of the Avatar component classes

public function personalization(): array
{
return Arr::dot([
'wrapper' => [
'class' => 'inline-flex shrink-0 items-center justify-center overflow-hidden',
'sizes' => [
'sm' => 'w-8 h-8 text-xs',
'md' => 'w-12 h-12 text-lg',
'lg' => 'w-14 h-14 text-2xl',
],
],
'content' => [
'image' => [
'class' => 'shrink-0 object-cover object-center text-xl',
'sizes' => [
'sm' => 'w-8 h-8 text-sm',
'md' => 'w-12 h-12 text-lg',
'lg' => 'w-14 h-14 text-2xl',
],
],
'text' => [
'class' => 'font-semibold',
'colors' => [
'colorful' => 'text-white',
'white' => 'text-neutral-700',
],
],
],
]);
}

All component classes are divided into class blocks applicable to their appropriate required locations in the Blade file associated with the component. TallStackUI was designed with soft personalization in mind: an easy way to personalize components, so even if the developer is a beginner, he doesn't need to have difficulty personalizing the components.

Let's take a look at an example:

use TallStackUi\Facades\TallStackUi;
 
class AppServiceProvider extends ServiceProvider
{
public function boot(): void
{
// ...
 
TallStackUi::personalize()
->form('input')
->block('input.class.base', 'w-full rounded-full');
 
// or...
 
TallStackUi::personalize('form.input')
->block('input.class.base', 'w-full rounded-full');
}
}

In this example we are touching and replacing all the classes in the input.class.base block of the input component with the content: w-full rounded-full . This means that every input component displayed on the application pages will have these classes, instead of the original component classes.

Just like Pest, TallStackUI offers a concept of fluency when using the and like a property or method:

use TallStackUi\Facades\TallStackUi;
 
class AppServiceProvider extends ServiceProvider
{
public function boot(): void
{
// 1. Property
 
TallStackUi::personalize()
->form('input')
->block('input.class.base', 'w-full rounded-full')
->and
->avatar()
->block('wrapper.sizes.sm', 'w-8 h-8 text-xs')
 
// 2. Method
 
TallStackUi::personalize()
->form('input')
->block('input.class.base', 'w-full rounded-full')
->and()
->avatar()
->block('wrapper.sizes.sm', 'w-8 h-8 text-xs')
}
}

The idea behind this approach is to personalize more than one component at the same time.

You can personalize one block at a time or all at once:

use TallStackUi\Facades\TallStackUi;
use App\TallStackUi\InputPersonalization;
 
class AppServiceProvider extends ServiceProvider
{
public function boot(): void
{
TallStackUi::personalize()
->form('input')
->block('input.class.base', new InputPersonalization())
->block('icon.wrapper', fn (array $data) => 'px-4 py-2')
->block('icon.paddings.left', 'pl-10');
 
// or ...
 
TallStackUi::personalize()
->form('input')
->block([
'input.class' => new InputPersonalization(),
'icon.wrapper' => fn (array $data) => 'px-4 py-2',
'icon.paddings.left' => 'pl-10',
]);
}
}

You may have noticed that in the example above we used the InputPersonalization class. This is a simple invokable class, because TallStackUI also allows you to make your personalization into classes. This approach is ideal if you are someone who prioritizes organization above all else. Let's take a look at an example:

1. Preparing:

use TallStackUi\Facades\TallStackUi;
use App\TallStackUi\InputPersonalization;
 
class AppServiceProvider extends ServiceProvider
{
public function boot(): void
{
TallStackUi::personalize()
->form('input')
->block('input.class.base', new InputPersonalization());
}
}

2. Personalizing:

namespace App\TallStackUi;
 
use TallStackUi\Contracts\Personalizable;
 
class InputPersonalization implements Personalizable
{
public function __invoke(array $data): string
{
return 'w-full rounded-full';
}
}

You may have noticed that the example above there is a variable called $data . This variable is an array containing all the component's properties, including the values passed when you used the component somewhere in your application.

Using the input like this:

<x-input label="Name" hint="Your full name" />

The $data will be something like:

[
"id" => null
"label" => "Name"
"hint" => "Your full name"
"icon" => null
"position" => "left"
"validate" => true
"componentName" => "input"
"attributes" => \Illuminate\View\ComponentAttributeBag [...]
"personalization" => \Illuminate\View\InvokableComponentVariable [...]
"colors" => \Illuminate\View\InvokableComponentVariable [...]
"configurations" => [...]
"slot" => \Illuminate\View\ComponentSlot [...]
"__laravel_slots" => [...]
]

You can use this to interact with your personalization.

Although all the examples above are valid, they overwrite the original block classes by defining the second parameter of the block method, this is a way of doing a complete replacement of the original component classes by the blocks, an expected behavior when the soft personalization was created. Luckily we have an easy way to interact with the original classes by touching their content but preserving everything else. Let's take a look at an example:

use TallStackUi\Facades\TallStackUi;
 
class AppServiceProvider extends ServiceProvider
{
public function boot(): void
{
TallStackUi::personalize()
->form('input')
->block('input.class.base')
->replace('rounded-md', 'rounded-full');
 
// or...
 
TallStackUi::personalize()
->form('input')
->block('input.class.base')
->replace([
'rounded-md' => 'rounded-full',
'border-0' => 'border-1',
]);
}
}

Note that in the example above we omitted the second parameter of the block method, this way we can access four useful methods that allow us to touch the component's original classes in an easy way in order to make modifications while maintaining the rest of the original content.

All the four methods:

use TallStackUi\Facades\TallStackUi;
 
class AppServiceProvider extends ServiceProvider
{
public function boot(): void
{
TallStackUi::personalize()
->form('input')
->block('input.class.base')
// string or array
->replace('rounded-md', 'rounded-full')
// string or array
->remove('w-full')
// string
->append('px-4')
// string
->prepend('py-4');
}
}

Now that these methods have been introduced, let's imagine that you want to transform all your inputs into a fully round style to follow the look of your application, so all the work (🥵) you need to do is:

use TallStackUi\Facades\TallStackUi;
 
class AppServiceProvider extends ServiceProvider
{
public function boot(): void
{
TallStackUi::personalize()
->form('input')
->block('input.class.base')
->replace('rounded-md', 'rounded-full');
}
}

Without spending a lot of time, without a lot of effort, without a lot of technical knowledge you have just achieved your goal in an extremely quick, expressive and direct way. Isn't that amazing? 😎

Although soft personalization is powerful and easy to use, there is one problem: all soft personalization is applied to all components, and it is not possible to assign specific personalization to a component only once. Therefore, starting from version 1.9.0 you can set the scoped personalization. Just as in VueJS where we have CSS scoped, CSS applied only to the component to be defined, TallStackUI offers the personalize attribute in all components allowing interaction with the classes so that the personalization is applied only to the component that defines the personalization. Let's take a look at an example:

<!-- Displaying a normal Alert component -->
<x-alert>This is a normal Alert component</x-alert>
 
<!-- Displaying a fully round alert component -->
<x-alert :personalize="[
'wrapper' => [
'replace' => [
'rounded-lg' => 'rounded-full',
],
]
]">
This is a fully round Alert component
</x-alert>

Considering this code above, then this will be the result:

This is a normal Alert component

This is a fully round Alert component

Just like soft personalization, scoped personalization needs to target a specific block that will receive the personalization. Let's take a look at other examples and possibilities:

<x-alert :personalize="[
{{-- Override all content --}}
'content.wrapper' => 'flex items-start',
'wrapper' => [
{{-- Replacing --}}
'replace' => [
'rounded-lg' => 'rounded-full',
],
],
'text.title' => [
{{-- Removing --}}
'remove' => 'text-lg',
],
'text.description' => [
{{-- Appending --}}
'append' => 'p-4',
],
'icon.size' => [
{{-- Prepending --}}
'prepend' => 'mr-4',
]
]">
This is a fully personalized Alert component
</x-alert>

Unlike soft personalization, scoped personalization will not throw an exception when the block to be personalized does not exist. Therefore, if there is an error in the block name or wrong block name, the application will not generate a visual error for the end user, the personalization will just not be applied.

Starting from version 1.30.0 you can pass a class name that contains a __invoke public method to the personalize attribute to make the personalization more organized and reusable. Let's take a look at an example:

Blade:

<x-alert :personalize="\App\ScopedPersonalization\Alert::class" />

PHP:

namespace App\ScopedPersonalization;
 
class Alert
{
public function __invoke(array $classes): array
{
return [
'wrapper' => [
'replace' => [
'rounded-lg' => 'rounded-full',
],
],
];
}
}

You may have noticed that in the example above we have an array called $classes as the parameter of the __invoke method, this array is an array with all classes that came from the original personalization defined to the component.

If you are personalizing your components, there is something you should know. As classes are TailwindCSS classes you need to ensure that TailwindCSS watches the files from which the classes you defined come, so personalization will take effect. To do this, you must edit your tailwind.config.js file inserting this content:

content: [
// If you are personalizing into AppServiceProvider or other
 
'./app/Providers/MyCustomServiceProvider.php',
'./app/Providers/AppServiceProvider.php',
 
// If you are using invokable classes...
 
'./app/TallStackUi/**/*.php',
],

All component documentation mentions their respective blocks in a button at the top of each page.

Code highlighting provided by Torchlight