No
Scoped CSS in Livewire Component
I know how to use (scoped) css in vue component. But is there any chance to use css in Livewire Component like vue component?
No, this feature is not available out of the box.
You could try mimicking that yourself, but I don't think it would be robust enough as the Vue solution.
A proof-of-concept:
php artisan make:livewire ScopedComponent
<?php
namespace App\Http\Livewire;
use Illuminate\Support\Str;
use Livewire\Component;
class ScopedComponent extends Component
{
public $cssScope;
public function mounted()
{
// initialize a scope at mount
$this->cssScope = Str::random();
}
public function render()
{
return view('livewire.scoped-component');
}
}
<div id="scope-{{ $cssScope }}">
<p>Hello world</p>
<ul>
<li>Foo</li>
<li>Bar</li>
<li>Baz</li>
</ul>
<style>
/* you will need to apply scopes yourself manually */
#scope-{{ $cssScope }} p {
color: red;
}
#scope-{{ $cssScope }} li:first-child {
color: green;
}
#scope-{{ $cssScope }} li:last-child {
color: blue;
}
</style>
</div>
The main difference is that Vue applies the generated hash as a data- attribtue for each child element, where here I chose to add just an id to the root component.
Also Vue automatically transforms the CSS to inject the generated hash, while here I added manually to each CSS selector.
Hope it helps.
Hi, rodrigo, Thank you. I have found an Idea.
Can you make a pull request to make it available in future?
Sorry, I don't quite understand what you mean.
You mean making a Pull Request to Laravel Livewire to add this feature?
I don't think it is something they would want to maintain in the long run due to the amount of caveats that can happen.
For example, in this sample I added an id to the root element, this might not be desirable as people would want to add their own ids. Adding a data- attribute, such as Vue does, to every child HTML element inside a component, is trickier to get right by template parsing on the PHP side without any user manual code modification.
For example, one could use a blade @\include directive inside the template to inject another template content, and to have scoped CSS right we might need to add the data- attributes to the injected elements, how to do that if the generated PHP code does not actually inject the content but adds code to require that template at runtime.
Also which would be the best approach to handle nested components? Vue solves that by adding both scope hashes to a nested component's root element, that would be very hard to do only on PHP side.
In the code sample it kind of works as I resorted on using the id attribute on the root element which has a high CSS specificity value, but to handle a generic use-case this solution is not the best way to go.
Also one big implementation difficulty is appending the hash to all CSS rules contained in a <style> block. In the code sample I added them manually, which does the work, but doing it automatically would require parsing a CSS block, extract the selectors and modify them before rendering the template, which could lead to a lot of corner cases, and undesirable CSS conflicts. As I added an id to the root element, adding them manually is an easy task as we just need to add in the beginning of each CSS selector, but if the best way to go is to use data- attributes, the hash might be needed to be added at the end or in the middle of a CSS selector.
Maybe it would be easier to do add to the JavaScript part of Livewire, but I am not familiar with that. Doing it i the browser is a bit easier as using the DOM API to parse CSS rules and modify DOM elements is a built-in feature browsers have.
If that was the plan, I am sorry, I don't have the availability or sufficient knowledge to do this contribution in a manner I think it is maintainable by the Livewire project.
But you can try to open an issue and proposing this as a feature request to see if Livewire's maintainers would consider adding this in a much clever way that handle the generic use case.
Right now no similar feature is planned their roadmap:
https://github.com/livewire/livewire#roadmap
Hope it is clear.
Please or to participate in this conversation.