Reputation: 1482
I have HTML like this:
<div class="form-group">
<input type="email" class="form-control>
<div class="form-error">This is not valid email address</div>
</div>
I am printing div.form-error
dynamically if the input has errors.
I need CSS code to make the input's border red if there is a div.form-error
in the div.form-group
.
I'am working with SASS, maybe it has a function to do this. I'm looking for a something like this:
.form-group {
&:contains('.form-error') {
input {
border: 1px solid red;
}
}
}
How can I do it?
Upvotes: 1
Views: 74
Reputation: 253426
Okay, so while my comment still stands – it is not possible to use CSS to style a previous sibling, or ancestor, based on a subsequent sibling or descendant – there is a way around it. Though it while it does require a change of your HTML it will still emulate the element-order that you posted in your question.
That said, the HTML is changed from the following:
<div class="form-group">
<input type="email" class="form-control" />
<div class="form-error">This is not valid email address</div>
</div>
To:
<div class="form-group">
<div class="form-error">This is not valid email address</div>
<input type="email" class="form-control" />
</div>
.form-group {
/* to use the flex layout model: */
display: flex;
/* to have the elements arranged
in a column instead of a row
(which you may or may not want): */
flex-direction: column;
/* aesthetics, adjust to taste: */
width: 50%;
border: 1px solid #000;
margin: 0 0 0.5em 0;
}
.form-group .form-error {
/* places the .form-error element(s)
at the end of the layout in position
2, which causes the <input> to take
position 1; note that the elements
are still in the same place for CSS
selection: */
order: 2;
}
/* This styles the email <input> element if
it follows the .form-error element: */
.form-error + input[type=email] {
border-color: red;
}
<div class="form-group">
<div class="form-error">This is not a valid email address</div>
<input type="email" class="form-control" />
</div>
Incidentally it's worth noting that according to caniuse.com, flexbox is available in all current browsers; though your users may not have updated their own browsers to the current (or previous) version as of writing.
There are, of course, other ways you can achieve this simply using the :invalid
pseudo-class:
/* Selects any <input> element whose value is invalid: */
input:invalid {
border-color: red;
}
<div class="form-group">
<input type="email" class="form-control" />
<div class="form-error">This is not a valid email address</div>
</div>
And, of course, you can even use fading to show or hide the error message:
/* Selects any <input> element whose value is invalid: */
input:invalid {
border-color: red;
}
/* hides the .form-error element using the opacity
property which takes a value, which allows it
to be animated from hidden (opacity: 0) to shown
(opacity: 1): */
.form-error {
/* visually hidden: */
opacity: 0;
/* specifies that the opacity property should be
transitioned over a 0.3 second time in a linear
animation: */
transition: opacity 0.3s linear;
}
/* Selects the .form-error element that immediately
follows an <input> which is :invalid */
input:invalid+.form-error {
opacity: 1;
}
<div class="form-group">
<input type="email" class="form-control" />
<div class="form-error">This is not a valid email address</div>
</div>
Bibliography:
Upvotes: 1
Reputation: 2656
As pointed out correctly by folks in the comments, you will need to alter mark up for this to work. You can use the sibling
selector:
https://developer.mozilla.org/en/docs/Web/CSS/Adjacent_sibling_selectors
.form-group {
.form-error + input {
border: 1px solid red;
}
}
.form-error + input {
border: 1px solid red;
}
<div class="form-group">
<div class="form-error">This is not valid email address</div>
<input type="email" class="form-control" />
</div>
Upvotes: 0
Reputation: 3811
You can use child selectors and sibling selectors.
For your example:
.form-group {
.form-error ~ input {
border: 1px solid red;
}
}
Upvotes: 0