Styling in the Loki Checkout is handled via Tailwind CSS classes - for both Hyvä and Luma themes! This means that the PHTML templates actually contain the CSS classes to keep in the Tailwind CSS build, which again means that - normally - template overrides would be needed for the simplest thing. Loki Checkout tries to keep template overrides to a minimum. It does so by adding clever PHP utilities that allow you to modify various CSS classes in the XML layout instead.
$css()
utilityIn every single PHTML template of the Loki Checkout, a new PHP variable $css
is added which is actually an instance of the class \Yireo\LokiCheckout\Util\Block\CssClass
which is invokable, as in, it behaves like a function:
$css('foobar')
The CSS classes you would add to this function will be outputted, unless they are actually overwritten in the XML layout. A real-life example usage of the utility might look like this:
File example.phtml
:
<div class="<?= $css('field w-auto relative') ?>"></div>
By default, this will simply output the CSS classes as-is in the browser:
<div class="example field w-auto relative"></div>
Note that an additional CSS class example
is automatically added as well, based on the XML layout name of the block that defined this template. (This only works if the scope is block
which is explained later on.)
File loki_checkout.xml
:
<block name="example" template="Yireo_LokiCheckout::example.phtml" />
However, with the example above, we can also add new values easily as such. Take for example the prefix
block:
<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:View/Layout:etc/page_configuration.xsd">
<body>
<referenceBlock name="loki.checkout.shipping-step.shipping-address.prefix">
<arguments>
<argument name="css_classes" xsi:type="array">
<item name="block" xsi:type="array">
<item name="color" xsi:type="string">bg-zinc-100 border border-zinc-200</item>
</item>
</argument>
</arguments>
</referenceBlock>
</body>
</page>
Within the item definition, the name color
is actually not important, only the value of the item is important. And you can see that one item definition is able to hold multiple CSS classes.
Now the HTML will look like the following:
<div class="example field w-auto relative bg-zinc-100 border border-zinc-200"></div>
In short, first the block identifier, then the default CSS (which was passed from the PHTML template) and then the additional CSS from the XML layout.
What about overriding CSS classes? For this, it is important to know that the item name default
can be used to override the default CSS (which was passed from the PHTML template).
<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:View/Layout:etc/page_configuration.xsd">
<body>
<referenceBlock name="loki.checkout.shipping-step.shipping-address.prefix">
<arguments>
<argument name="css_classes" xsi:type="array">
<item name="block" xsi:type="array">
<item name="default" xsi:type="string">field w-100 relative</item>
<item name="color" xsi:type="string">bg-zinc-100 border border-zinc-200</item>
</item>
</argument>
</arguments>
</referenceBlock>
</body>
</page>
Now the HTML will look like the following:
<div class="example field 100 relative bg-zinc-100 border border-zinc-200"></div>
What if you want to use the $css()
utility multiple times in the same PHTML template? Then you need to add a scope. By default, the scope block
is being used ($css('foobar', 'block')
), but you can refer to other scopes easily. The following example defines a new scope inner-span
:
<div class="<?= $css('field w-auto relative') ?>">
<span class="<?= $css('text-xl', 'inner-span') ?>"></span>
</div>
Now, within the XML layout, the CSS classes of the inner-span
scope can be extended like follows:
<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:View/Layout:etc/page_configuration.xsd">
<body>
<referenceBlock name="loki.checkout.shipping-step.shipping-address.prefix">
<arguments>
<argument name="css_classes" xsi:type="array">
<item name="inner-span" xsi:type="array">
<item name="default" xsi:type="string">text-2xl</item>
</item>
</argument>
</arguments>
</referenceBlock>
</body>
</page>
Scopes are only relevant when it comes to overriding or extending CSS classes via the XML layout.
If you are making a lot of changes to CSS classes of blocks, even the mechanism mentioned so far could lead to a lot of code duplication. A final resort is to make CSS class changes via the global block loki-components.css_classes
instead. This block is never shown on the page, but is simply used as a temporary storage for CSS classes. Each argument
represents a block ID (for example loki-checkout.example
) with all of the item
configurations below that being CSS class sections as explained above:
<referenceBlock name="loki-components.css_classes">
<arguments>
<argument name="loki-checkout.example" xsi:type="array">
<item name="block" xsi:type="array">
<item name="foobar" xsi:type="string">foobar</item>
</item>
</argument>
</arguments>
</referenceBlock>
To make things even more flexible, default CSS classes can be set for specific templates. Take for example the PHTML template Yireo_LokiCheckout::form/field.phtml
which is actually reused by every LokiComponent representing a field. Instead of making changes for every single form field, you could also just apply the CSS changes to the PHTML template. And then later override or extend the CSS classes for specific block instances.
For this, the following mechanism applies. The original template Yireo_LokiCheckout::form/field.phtml
is stripped from its module prefix (form/field.phtml
). Next, the PHTML suffix is removed (form/field
) and slashes are turned into dots (form.field
). This identifier is then prefixed with loki-components.defaults.
. The final block ID is loki-components.defaults.form.field
. If this block exists in the layout, it is taken into account while parsing CSS classes.
<block name="loki-components.defaults.form.field">
<arguments>
<argument name="css_classes" xsi:type="array">
<item name="block" xsi:type="array">
<item name="grid" xsi:type="string">col-span-6</item>
</item>
</argument>
</arguments>
</block>
And ofcourse, you can add in the XML layout a referenceBlock
instruction to make changes to this.