CSS BEM

BEM stands for Block, Element, Modifier. It is a convention on how to structure CSS rules. Read more here.

For Turnkey, the natural Block in BEM is one placed ViewModel column/widget/control.

Out of the box (this is extended with UI overrides), you will see these Blocks:

BEM_BlockName.Add(CSSControlType.ctStaticText, "tk-static-text");
BEM_BlockName.Add(CSSControlType.ctImage, "tk-image");  //new
BEM_BlockName.Add(CSSControlType.ctTextEdit, "tk-text-field");
BEM_BlockName.Add(CSSControlType.ctCheckbox, "tk-checkbox");
BEM_BlockName.Add(CSSControlType.ctDatePicker, "tk-datepicker"); //new
BEM_BlockName.Add(CSSControlType.ctCombobox, "tk-select");
BEM_BlockName.Add(CSSControlType.ctGrid, "tk-data-table");
BEM_BlockName.Add(CSSControlType.ctGroupbox, "tk-groupbox"); //new
BEM_BlockName.Add(CSSControlType.ctButton, "tk-button");
BEM_BlockName.Add(CSSControlType.ctFile, "tk-file-upload");
BEM_BlockName.Add(CSSControlType.ctLink, "tk-link");
BEM_BlockName.Add(CSSControlType.ctTextArea, "tk-textarea"); //new  , multiline text
BEM_BlockName.Add(CSSControlType.ctNumberEdit, "tk-number-field"); //new
BEM_BlockName.Add(CSSControlType.ctFloatNumberEdit, "tk-float-field"); // new

A Block is the outer div that we place in the CSS grid to position it in the same position you designed it to be.

The Element in BEM is then the inner parts of a BEM Block.

You will typically find these elements inside blocks in Turnkey-generated HTML:

BEM_ElementName.Add(CSSBEMElement.bEm__native, "__native");  // the actual html control
BEM_ElementName.Add(CSSBEMElement.bEm__interactive, "__interactive");  // the html control the user can change, similair to __native but for certain controls (checkbox) the __native is hidden and a span is __interactive
BEM_ElementName.Add(CSSBEMElement.bEm__label, "__label");  // the label
BEM_ElementName.Add(CSSBEMElement.bEm__content, "__content");  // enclosing inner div 

Looking at HTML to exemplify, we will get this HTML:

<div class="tk-component tk-text-field">
    <label class="tk-text-field__label">Name</label>		
    <input class="tk-text-field__native">
</div> 

And it will be default rendered like this:

2019-06-30 12h05 50.png

The aim of our BEM approach is to allow you to target a single element inside a specific block in order to override the style to your needs.

The third letter of BEM is Modifier. A Modifier is in the BEM convention typically described as an additional appendix to the element rules. In Turnkey, we treat all the style references that you add in the Designer as Modifiers. These modifiers will be added as separate classes to block levels to make it easier for you to create modifier styles that match a block or element within a block by normal CSS rules.

Match All Turnkey-controls, Disregarding the Type of Control

To match all Turnkey-controls - regardless of the type of control - placed by the CSSGrid for the ViewModel, you can use .tk-component. The tk-component CSS class is added to all BEM-Blocks.

If you want to style all <label> used by turnkey controls: .tk-component label{}

Our BEM Strategy

In our BEM strategy, we follow the "intent of BEM" rather than "BEM by the letter". Consider, if you have a text box control on a ViewModel and get this HTML:

<div class="tk-component tk-text-field">
    <label class="tk-text-field__label">Name</label>		
    <input class="tk-text-field__native">
</div> 

Now, add a style reference in your ViewModel column: "red". We consider "red" to be a Modifier-style and your HTML will now look like this:

<div class="tk-component tk-text-field red">
    <label class="tk-text-field__label red">Name</label>		
    <input class="tk-text-field__native red">
</div> 

In "true" BEM, we would expect this HTML:

<div class="tk-component tk-text-field tk-text-field--red">
    <label class="tk-text-field__label tk-text-field__label--red">Name</label>		
    <input class="tk-text-field__native tk-text-field__native--red">
</div>

Our standpoint is that the explicit modifier tk-text-field--red style brings no additional benefit that we cannot get by simply using the tk-text-field.red in CSS.

The CSS rules will look like this in the two cases:

CSS rule Comment
.tk-text-field__label.red Match labels for text field controls that has modifier red This is how we do it
.tk-text-field__label--red Match labels for text field controls that has modifier red We do not do this since the above rule is just as easy and requires fewer unique styles

It has been proposed that we should add the modifier ONLY to the outer div like this (this was more like our old strategy):

<div class="tk-component tk-text-field red">
    <label class="tk-text-field__label">Name</label>		
    <input class="tk-text-field__native">
</div> 

We have chosen to abandon this strategy since this strategy leads to CSS rules looking less like BEM rules:

CSS rule Comment
.red tk-text-field__label To match the label intended to be red, we now need to write red in front of the Element specifier - and this a far from what BEM suggests
.tk-text-field__label--red This is what the BEM convention stipulates
.tk-text-field__label.red This is what we do - very BEM-like and true to the general idea of Block__Element--Modifier

Possible Breaking Changes Introduced 2019-06-30

We aim to keep backward compatibility - this time, we needed to harmonize according to the BEM convention.

Was Is
.tk-button .tk-button__native
.tk-button.tk-button--narrow .tk-button__native--narrow
.tk-checkbox__label .tk-checkbox__content the style did not target the label surrounding the __native
.tk-checkbox .tk-checkbox__interactive
.tk-data-table .tk-data-table__content the style targets the div containing the table
.tk-data-table__content .tk-data-table__native this is the true table
.tk-select__native-control .tk-select__native native-control should be native as everywhere else
.tk-text-field .tk-text-field__native

If you need to adapt your old CSS to our new standard, chances are you can do so by changing modifier style rules from ".red" to match block div with ".tk-component.red" instead.

This page was edited 157 days ago on 06/17/2024. What links here