Ninja Tips 3 - [hidden] vs Bootstrap's help-block
Like everybody, you code enterprise software for a living (because everybody know you can't make a living by building videogames). And as you're not very good at designing web pages, you enjoy using CSS frameworks like Bootstrap, providing best practices for free, and a nice design without thinking about it. Alright, your websites are not very original (some say Bootstrap is the new ugly), but thanks to it you're productive. Don't blame yourself, I do exactly the same (maybe we're too old for this internet shit).
So you get to build this login form with Angular and Bootstrap. The HTML template, if using a model-driven form instead of a template-driven one, may look like:
<form (ngSubmit)="login()" [ngFormModel]="loginForm">
<div class="form-group">
<label for="username">Login</label>
<input id="username" type="text"
class="form-control" ngControl="username" required>
</div>
<div class="form-group">
<label for="password">Password</label>
<input id="password" type="password"
class="form-control" ngControl="password" required>
</div>
<button type="submit" class="btn btn-primary">
Sign me in
</button>
</form>
Congratulations, you've even thought about adding the required on both <input> elements.
Modern browsers should prevent from submitting this form with empty inputs.
But some feedback wouldn't hurt the user experience.
So you're trying to add some help text, to explain that these fields are mandatory.
Bootstrap even has an .help-block class,
which purpose is exactly this:
<div class="form-group">
<label for="password">Password</label>
<input id="password" type="password"
class="form-control" ngControl="password" required>
<span class="help-block">
Password is required
</span>
</div>
But as soon as this form is displayed, this help text is displayed, even if the user has not typed anything yet. At Ninja Squad, we like to have those hints and error messages be displayed only when the user has started to input something, to keep a clean form when entering the page. You may then leverage the validation capabilities of a super-charged Angular form:
<div class="form-group"
[ngClass]="{
'has-error': password.dirty
&& !password.valid }">
<label for="password">Password</label>
<input id="password" type="password"
class="form-control" ngControl="password">
<span class="help-block"
[hidden]="password.pristine
|| !password.hasError('required')">
Password is required
</span>
</div>
<button type="submit" class="btn btn-primary" [disabled]="!loginForm.valid">
Sign me in
</button>
What are we doing here?
- We apply, thanks to the
ngClassdirective, the Bootstrap's.has-errorclass ondiv.form-groupif thepasswordfield:- is
dirty, i.e. modified by the user; - has a validation error.
- is
- We enable the submit button only if the form is globally valid, thanks to the
disabledDOM property. - We hide the
span.help-blockelement thanks to the HTML 5hiddenglobal attribute, if:- the input is
pristine, i.e. without any modification from user (the initial state); - or if the field has no
'required'validation error.
- the input is
Cool! Unless... that does not really work.
The span.help-block will always be displayed, even with a pristine input, even without any validation error.
That is not an error in the condition.
That is not your browser not implementing this HTML 5 hidden attribute.
That is also not an Angular binding bug on this HTML 5 attribute.
This issue gave me some cold sweat,
that's why I wanted to share this ninja tip with you, be it very anecdotic.
The issue is between the HTML 5 hidden global attribute behavior,
and the styles brought by Bootstrap's .help-block class.
The hidden documentation explains :
changing the value of the CSS
displayproperty on an element with thehiddenattribute overrides the behavior.
And, indeed, the help-block class brings the
display: block; style (source)...
That's why your help text is always displayed, even if your usage of Angular validation is perfect.
OK, cool! So now what?
You can either get rid of the help-block class (but you'll lose the style),
or you can rewrite your template to not use hidden attribute anymore.
And that's when the ngIf directive comes to play:
<span class="help-block"
*ngIf="password.dirty
&& password.hasError('required')">
Password is required
</span>
Et voilà !
Of course, we needed to negate the initial condition of [hidden]="..." (but that's Boole Algebra 101),
and we replaced the pristine test by a dirty test, which is the exact opposite.
Thomas Queste suggested in the comments an other solution seen on StackOverflow: simply wrapping the error message in its own
spaninside thespan.help-block.
Thanks for the time you spent listening to me. I feel better now. You may get back to work, or get back to read our Angular ebook.
← Older post
Newer post →
Our books on sale


Next training sessions
- From Nov 17 to Nov 20, 2025Angular: Ninja to Hero (remote)
- From Dec 1 to Dec 4, 2025Vue: Zero to Ninja (remote)
- From Dec 8 to Dec 11, 2025Angular: Zero to Ninja (remote)
- From Jan 19 to Jan 22, 2026Angular: Ninja to Hero (remote)
- From Feb 9 to Feb 12, 2026Vue: Zero to Ninja (remote)
- From Mar 2 to Mar 5, 2026Angular: Zero to Ninja (remote)
