Problem/Motivation

Each field that comes out of care has a head load of templates coming out - some of them are usefull , where others are overkill. We can do better & make it easier for a themer to add the classes thats needed without loosing the flexibility.

now a field is wrapped in something like this:

<div class="field field-node--body field-name-body field-type-text-with-summary field-label-hidden edit-processed edit-field" data-edit-field-id="node/1/body/en/teaser">
  <div class="field-items">
    <div class="field-item">

      <p>lorem...</p>

    </div>
  </div>
</div>

Thats 4 classes to describe the field & one to tell us what happens with the label.

.field
a class to tell us its a field - well thats great drupal but what should i use that for ?

If a themer wants to add this field it can be added easy to the field.twig.html file (see the example later)

.field-node--body
a class that its a specific type of field (body) in a node (vs a user ?)
Is this a thing anybody is actually gonna do - Atm we allready have a class wrapper around the element that tells us if this is a node / user etc.

We could remove this as well to be easy to add to the field wrapper in the template.

.field-name-body
a class that tells us what the specific name for this field.
Very usabable.

.field-type-text-with-summary
A class that tells us the "widget"

.field-label-hidden
a class to tell us where the label is placed in the wrapper

Proposed resolution

As basic wrappers that have very few default classes, it makes it easy and simple.

.field-{{ name }}
The unique name for the field, make sense to target that individually.

field-type-{{ fieldtype }}
The name for that fieldtype, makes it easy to work with common elements

.field-label-{{ label-position }}
The field label have a ui controller its not the role of this issue to do anything about that - if somebody wants to do that open up a seprate issue, adding it to the wrapper makes it easy for a themer to control the whole field.
the class dont exist if theres not a label added from the ui

This will make the markup very readable & still highly customizable.

If the themer needs more specifix classes they can easy be added to the classe for the field.

{{ fieldtype }} 
{{ multiplevalues }} 
{{ viewmode }}
{{ formatter }}

css quick examples
grap all the fields and add a border:

div[class="field-*"]{ 
  border-bottom:1px solid pink 
}

change the label behaviour

.field-label-inline .field-label{ display:inline-block } 
.field-label-above .field-label{ display:block } 

variations for a node vs a user:

.node-viewmode .field-{{ name }}{ ... }
.user-viewmode .field-{{ name }}{ ... }

field.twig

  <div class="field-{{ name }} field-type-{{ fieldtype }} .field-label-{{ label-position }} {{ attributes.class }}" {{ attributes }}>
    ....
  </div>
  <div class="look-ma-no-hands-{{ field-formatter }} field-{{ name }} field-type-{{ fieldtype }} .field-label-{{ label-position }} {{ attributes.class }}" {{ attributes }}>
    ....
  </div>

Remaining tasks

* Remove the classes - test if it actually breaks anything
* move the classes from the prepocess to a generic field.twig.html
* benchmark that it dosnt get slower
* enjoy less classes & easier for the themer to work in it

User interface changes

API changes

Comments

Sweetchuck’s picture

I think the "field type" and the "field widget" is not the same thing. So the example above is not correct.
And I think the kind of the "field widget" is not relevant when theming the output.

pdureau’s picture

IMO, we need in the view modes :

  • Field Name : field-name-{{fieldname}} (ex : field-name-body)
  • Field Type : field-type-{{fieldtype}} (ex : field-type-text-with-summary)
  • Field Formatter : field-formatter-{{fieldformatter}} (ex : field-formatter-text-trimmed)

We can remove .field and .field-{{entitytype}}--{{fieldname}}, for the reasons you gave.

Field Widgets belong to the form modes, no to the view modes.

xandeadx’s picture

I use only one class — field-name (ex: body, field-image). Other add as needed.

barraponto’s picture

IMO, we need in the view modes :

Field Name : field-name-{{fieldname}} (ex : field-name-body)
Field Type : field-type-{{fieldtype}} (ex : field-type-text-with-summary)
Field Formatter : field-formatter-{{fieldformatter}} (ex : field-formatter-text-trimmed)

We can remove .field and .field-{{entitytype}}--{{fieldname}}, for the reasons you gave.

Field Widgets belong to the form modes, no to the view modes.

Agreed, BUT div[class="field-*"] doesn't work. Also, .field doesn't hurt (although I have never used it).

mortendk’s picture

Issue summary: View changes
mortendk’s picture

adding classes because it dosnt hurt is how we ended up with a ton of classes for each field - div[class*="field-"]{...} works so its corrected now.

is there a usecase for adding a Fieldformatter as a class ?

andypost’s picture

Suppose formatter plugin ID makes sense, at least as prefixed somehow.
Entity reference fields are widely used in D8 and its 4 core formatters needs ability to be styled

mortendk’s picture

Issue summary: View changes

update of classnames in description with psedu code examples

LewisNyman’s picture

As far as I understand the CSS standards; we should only use two hyphens there is an original component that is being modified. For example field-{{ name }} would only make sense if there is a field class. If there is no CSS being shared between the different variations then we can just use single hyphens.

pdureau’s picture

is there a usecase for adding a Fieldformatter as a class ?

IMHO, it is more the field formatter we want to style than the field itself or the field type. We don't usually do that because the field formatter class is missing.

The field name is too narrow because its is too specific (many differents fields with the same style to set) and linked to the data model.
The field type is too wide because there could be plenty of very different formatters for only one field type (the 4 core formatters of entity reference, as andypost told us)

mortendk’s picture

can you add a couple of examples of the fieldformatter classes
Im trying to figure out a way that we can add in the least amount of classes from the beginnig but then make it exremely simple for the themer to add in classes as they are needed

sirviejo’s picture

+1 to this proposal.

Why:

- The actual situation of a huge amount of classes and the "dividitis" is an overkill, i understand this adds flexibility to properly target specific elements with our style. But when you compare the output of drupal with the output of the markup outputted by other major CMSs, ours is a lot more complex.
- This will make our DOM more lite. And as we are moving to a sort of mobile first approach, this will be a major boost.

Considerations:

- There could be a lot of modules depending on this markup, we need to chase those, and see how they will be affected by this changes. (Maybe we can create a module to revert this changes, to actual output)

Conclusion:
- Less is MORE
- Themers with specific needs, still be able to override within their own themes.

andypost’s picture

@sirviejo Please provide an examples of "other cms markup", seems we need to investigate here more...

rteijeiro’s picture

Title: Fields classes - what do we actually need & want in Druapl8 twig » Fields classes - what do we actually need & want in Drupal8 twig

Changed title. Everybody knows that "Durpal" is better :P

sirviejo’s picture

@andypost Let me grab you some examples and i will post them here

mortendk’s picture

Ladies gentleman Can we please keep this to the wrapper classes We dont want this issue to be a monolith path, the divitis issue is here: #2214241 so please take that discussion there, about markup & whatever other cms'es do ;)

This is Drupal Core so yes - whatever we decide here will effect how a lot of contrib modules will have to change their code - look at me wheep ;)
We are making radical changes to the whole of core anyways so lets make it epic for the themers as well.

Usecases
What we need is realistic user case so we hit the 80% of the need NOT 100% out of the box.
and at the same time make sure its easy to add the very specific variations can be created in the theme.

what i would like to se was the classname printed directly into the template & with an attributes.class in the end, so if a module need a specific class to work its can be added that way.
so the template file would look like this
class="{{ field-name }} {{ field-type}} {{field-label-position}} {{attributes.class }}"
(in the field.html.twig file)

if the themer then have other variables ready for what might be needed later like {{ field-formatter }} {{field-viewmode }} etc.

Then its easy to figure out wtf is going on in the field.twig file. it a themer wants more classes added to ALL the fields, its easy to add em (but that need should not pester the rest of the 2% of the web)

LewisNyman’s picture

I'm happy with these proposals. .field, field-node--body, and .field-type-text-with-summary are rarely useful. I'm not sure I've ever used them personally.

barraponto’s picture

Upon discussing with @rteijeiro and @mortendk on IRC, we found that the only way to target every field without .field would be div[class^='field-'],div[class*=' field-']. It means targeting node entities within fields (rendered entity formatter) would be div[class^='field-'] .node, div[class*=' field-'] .node. Awful, any sane CSS dev would add the .field selector back. This is an imagined example, though. I'd like to check if contributed themes in D7-land use .field before taking it out.

As for .field-{{entity-type}}-{{field-name}}, I think it's redundant since fields usually come inside the context of the rendered entity (meaning .{{entity-type}} .{{field-name}} would be enough). I can only imagine Views adding fields outside of the entity context (and I would not be opposed to Views' preprocess adding this selector back in).

Finally, I think .field-{{widget-name}} should only be added to entity forms, while field-{{formatter-name}} should only be added to rendered entities.

mortendk’s picture

@barraponto
So can you explain what exactly you want & need .field class ?
it would be really great if there could be a good real world example of this , not a "this is how we always have done it"

Can i get a comment of the idea of removing all these predefined classes from a preprocess and putting it directly in to the template file, thats where the goal is here. (listed again in #17) - still keepin a modules ability to add in needed classes with {{ attributes.class }}

this is not about finding the 100% solutions to all problems, this is about finding a good solutions that themers can work with, without having to dig into drupals inner workings (aka php n stuff)

mortendk’s picture

Issue summary: View changes
LewisNyman’s picture

Split deciding the classes and moving the classes into the twig template in #2217731: Move field classes out of preprocess and into templates

mortendk’s picture

+1 this can turn into epic bikeshed

derheap’s picture

Just to provide some quick data:

find core -name "*.css" | xargs grep -R "\.field"

Lists all css rules with .field in core:

core/modules/content_translation/css/content_translation.admin.css:#language-content-settings-form table .field {
core/modules/content_translation/css/content_translation.admin.css:[dir="rtl"] #language-content-settings-form table .field {
core/modules/content_translation/css/content_translation.admin.css:#language-content-settings-form table .field label,
core/modules/edit/css/edit.theme.css:.edit-toolbar-label .field:after {
core/modules/field/css/field.module.css:.field .field-label {
core/modules/field/css/field.module.css:.field-label-inline .field-label,
core/modules/field/css/field.module.css:.field-label-inline .field-items {
core/modules/field/css/field.module.css:[dir="rtl"] .field-label-inline .field-label,
core/modules/field/css/field.module.css:[dir="rtl"] .field-label-inline .field-items {
core/modules/field/css/field.module.css:form .field-edit-link {
core/modules/field/css/field.module.css:form .field-multiple-table {
core/modules/field/css/field.module.css:form .field-multiple-table .field-multiple-drag {
core/modules/field/css/field.module.css:[dir="rtl"] form .field-multiple-table .field-multiple-drag {
core/modules/field/css/field.module.css:form .field-multiple-table .field-multiple-drag .tabledrag-handle {
core/modules/field/css/field.module.css:[dir="rtl"] form .field-multiple-table .field-multiple-drag .tabledrag-handle {
core/modules/field/css/field.module.css:form .field-add-more-submit {
core/modules/field_ui/css/field_ui.admin.css:.field-ui-overview .add-new .label-input {
core/modules/field_ui/css/field_ui.admin.css:[dir="rtl"] .field-ui-overview .add-new .label-input {
core/modules/field_ui/css/field_ui.admin.css:.field-ui-overview .add-new .tabledrag-changed {
core/modules/field_ui/css/field_ui.admin.css:.field-ui-overview .add-new .description {
core/modules/field_ui/css/field_ui.admin.css:.field-ui-overview .add-new .form-type-machine-name .description {
core/modules/field_ui/css/field_ui.admin.css:.field-ui-overview .add-new .add-new-placeholder {
core/modules/field_ui/css/field_ui.admin.css:.field-ui-overview .region-title td {
core/modules/field_ui/css/field_ui.admin.css:.field-ui-overview .region-message td {
core/modules/field_ui/css/field_ui.admin.css:.field-ui-overview .region-populated {
core/modules/field_ui/css/field_ui.admin.css:.field-ui-overview .region-add-new-title {
core/modules/field_ui/css/field_ui.admin.css:.field-ui-overview .add-new td {
core/modules/field_ui/css/field_ui.admin.css:.field-ui-overview .field-plugin-summary-cell {
core/modules/field_ui/css/field_ui.admin.css:.field-ui-overview .field-plugin-summary {
core/modules/field_ui/css/field_ui.admin.css:.field-ui-overview .field-plugin-summary-cell .warning {
core/modules/field_ui/css/field_ui.admin.css:.field-ui-overview .field-plugin-settings-edit-wrapper {
core/modules/field_ui/css/field_ui.admin.css:.field-ui-overview .field-plugin-settings-edit {
core/modules/field_ui/css/field_ui.admin.css:.field-ui-overview .field-plugin-settings-editing td {
core/modules/field_ui/css/field_ui.admin.css:.field-ui-overview .field-plugin-settings-editing .field-plugin-type {
core/modules/field_ui/css/field_ui.admin.css:.field-ui-overview .field-plugin-settings-edit-form .plugin-name {
core/modules/system/css/system.module.css:.fieldgroup {
core/themes/bartik/css/style.css:div.field-type-taxonomy-term-reference,
core/themes/bartik/css/style.css:.submitted .field-name-field-user-picture img {
core/themes/bartik/css/style.css:[dir="rtl"] .submitted .field-name-field-user-picture img {
core/themes/bartik/css/style.css:.field-type-taxonomy-term-reference {
core/themes/bartik/css/style.css:.field-type-taxonomy-term-reference .field-label {
core/themes/bartik/css/style.css:[dir="rtl"] .field-type-taxonomy-term-reference .field-label {
core/themes/bartik/css/style.css:.field-type-taxonomy-term-reference .field-label,
core/themes/bartik/css/style.css:.field-type-taxonomy-term-reference ul.links {
core/themes/bartik/css/style.css:.view-mode-teaser .field-type-taxonomy-term-reference .field-label,
core/themes/bartik/css/style.css:.view-mode-teaser .field-type-taxonomy-term-reference ul.links {
core/themes/bartik/css/style.css:.field-type-taxonomy-term-reference ul.links {
core/themes/bartik/css/style.css:.field-type-taxonomy-term-reference ul.links li {
core/themes/bartik/css/style.css:[dir="rtl"] .field-type-taxonomy-term-reference ul.links li {
core/themes/bartik/css/style.css:.field-type-image img,
core/themes/bartik/css/style.css:.field-name-field-user-picture img {
core/themes/bartik/css/style.css:.comment .field-name-field-user-picture img {
core/themes/bartik/css/style.css:[dir="rtl"] .comment .field-name-field-user-picture img {
core/themes/bartik/css/style.css:.profile .field-name-field-user-picture {
core/themes/bartik/css/style.css:.views-display-columns a.fieldset-title {
core/themes/bartik/css/style.css:.views-display-columns a.fieldset-title:hover {
core/themes/seven/style.css:#field-display-overview input.field-plugin-settings-edit {
core/themes/seven/style.css:#field-display-overview tr.field-plugin-settings-changed {
core/themes/seven/style.css:#field-display-overview tr.field-plugin-settings-editing {
core/themes/seven/style.css:#field-display-overview .field-plugin-settings-edit-form .form-item {
core/themes/seven/style.css:#field-display-overview .field-plugin-settings-edit-form .form-submit {
core/themes/seven/style.css:#system-modules .fieldset-wrapper {
core/themes/seven/style.css:details.fieldset-no-legend {

I have not much time right to to investigate further, but to me is obvious:
* .field is only used 2-3 times, and mostly in admin.
* most field- classes are extra classes for admin, we can inject them with {{attributes.class}}

So I am +1 for #17:

class="{{ field-name }} {{ field-type}} {{field-label-position}} {{attributes.class }}"

And I would reduce it in the normal field.html.twig to :

class="{{field-label-position}} {{attributes.class }}"

And provide the others ({{ field-name }} {{ field-type}}) as examples in field.html.twig

The Admin-Theme (Seven) can redefine field.html.twig or inject the classes in preprocess.

Keep it to the bare minimum in standard markup.

Cottser’s picture

Category: Feature request » Task
Issue tags: +sprint

Tagging for focus.

LewisNyman’s picture

Issue tags: +frontend, +html
lauriii’s picture

Assigned: Unassigned » lauriii
lauriii’s picture

Assigned: lauriii » Unassigned
andypost’s picture

Cottser’s picture

Issue tags: -sprint

Bump, anything need to be done here now that we have Classy and also #2214241: Field default markup - removing the divitis?

mortendk’s picture

what we should do was look into what we really want of classes wrapping and se how many we can remove out of the system

mortendk’s picture

Personally i would like to cook the classes down a little bit - First of all its really really really easy to add in classes as they are needed, so we should not be to afraid of cleaning up even more imho.

now a field is written like this
field field--name-[name] field--type-[type] field--label-hidden field__item"

if we look at a field as a "componen" - then it should be based on what kind of widget it is, so a theme would actually not use the name but use the kind of widget to write the css around:

1:field cause .field really ?
2:field--name-[name]the name is very specific to the single field
3:field--label-hidden afaik we dont really need this, we have it inside of the label so the wrapper dont really need it
field--type-[type] this is where the gold is.
field__itemto keep with the bem

maybe its to late to push this in right now ?

joelpittet’s picture

Status: Active » Closed (won't fix)

@mortendk wrote this:

we have fixed this in field.html.twig so this discussion is kinda redundant
/mdk

at BADCamp 2015

Triage theme system. If there is further class cleanup it may have to be done in D9 at this point.