torchbox / tbxforms

A Torchbox-flavoured template pack for django-crispy-forms, adapted from crispy-forms-gds.
https://pypi.org/project/tbxforms/
BSD 2-Clause "Simplified" License
6 stars 5 forks source link

I would like to be able to add my own class to a label #26

Open helenb opened 2 years ago

helenb commented 2 years ago

At the moment I can add my own classes to the form itself and to any form field, if I use a Layout I can also add arbitrary attributes if needed. But it seems I can't change the label class unless I write a custom template.

It would be good to have a way to do this - a lot of the headaches with form styling comes when we need to nest CSS, so anything we can do to avoid this is good.

kbayliss commented 2 years ago

You can add a class to the form by adding a form_class to the form's helper. For example, using the example from https://github.com/torchbox/tbxforms#add-a-submit-button-and-customise-the-form-via-the-helper-property you would do:

class YourSexyForm(TbxFormsBaseForm, forms.Form):
    @property
    def helper(self):
        fh = super().helper
        fh.css_class = "hello"
        return fh

https://django-crispy-forms.readthedocs.io/en/latest/form_helper.html contains a list of all the attributes you can set within a form's helper property.

You can also add classes to each individual field within the layout: Field("your_field", css_class="hello"). However, you cannot remove classes. Alternatively, a backend developer could work within the confines of Django Crispy Forms and create a bespoke solution if required.

helenb commented 2 years ago

Hey,

Thanks for the info - my question wasn't worded very clearly. I meant that I know already how to add classes to form element and to any form field, but what I can't do is add a class to the label element. It's that label class I'd love to be able to add without having to create a custom template. Is there any way to add this as an option in tbxforms, or is it not possible because crispy forms doesn't allow it?

Thanks.

kbayliss commented 2 years ago

Thanks for the extra info :). Could you explain the use case so I can better understand why adding a class to a label would be helpful?

Right now, you could do something like:

Div(
    Field("your_field_name"),
    css_id="some-id",
)
div#some-id label {
    color: red;
}

Would that be enough?

I would advise against creating a custom template as much as possible - this option should only be used in unique circumstances if you are doing something with an unsupported field, such as a new widget. Creating field templates will make your app harder to maintain and more prone to errors.

helenb commented 2 years ago

Hey @kbayliss,

Apart from the fact that we'd never ever use an id for styling 😛 , adding a class to a parent div and using that to target the label would be an option, but it's not ideal. The reason a class directly on the label is preferable is because we try to avoid nested CSS wherever feasible - it makes it harder to override, and in more complex builds it can quickly lead to quite tangled CSS code.

kbayliss commented 2 years ago

Haha, true! css_class is also supported in replace of css_id :).

How often do you need to override the CSS for a particular label?

I've just realised that in most cases you can avoid wrapping the Field in another element, so this should work too:

Field("your_field_name", css_class="hello"),
.hello label {
    color: red;
}
helenb commented 1 year ago

Sorry, I realise I never responded to this! And now I'm styling crispy forms again... basically we really don't want to be nesting CSS - we always want to avoid the cascade. So it would be really handy to style a label directly without nesting

helenb commented 1 year ago

There was a discussion about this on the #tech torchbox slack channel, as someone else was asking for the same thing. Apparently this is possible in the bootstrap theme, so ought to be possible for tbxforms too:

"Depending on the theme you are using, you can use a helper and the label_class attribute:

class InlineHelper(FormHelper):                                                 
    form_tag = False                                                            
    form_class = 'form-horizontal'                                              
    label_class = 'col-md-2 col-form-label'                                     
    field_class = 'col-md-10'

As you might have guessed from the class names, this is one of the bootstrap theme (bootstrap4 to be precise) Here's the link to the docs: https://django-crispy-forms.readthedocs.io/en/latest/form_helper.html#bootstrap-3-helper-attributes"

kbayliss commented 1 year ago

Apologies, Helen. I thought you wanted to set a class for an individual label, not all labels for a form.

Have you tried using label_class? It's in Django Crispy Forms core code, so it may work for tbxforms too. Just to clarify though, this will be for all labels within that form - not an individual field.

Let me know how you get on!

Also, a minor point of clarification - each template pack (tbxforms is a template pack, as is the GDS support and so is the bootstrap3 support) alters the behaviour of Django Crispy Forms and there is no requirement for all packs to support the same additional features. So just because Bootstrap supports something, that does not mean others should too. For instance, tbxforms and GDS packs has lots of behaviours that neither Bootstrap pack has, and there are plenty of things Bootstrap do that we do not support.

helenb commented 1 year ago

Ah thanks @kbayliss - I was really looking for something that will set a class on an individual label field - but for the whole form is better than no class!