Some form styles and animations for labels and error states
Created
August 24, 2022 06:12
-
-
Save LaunchedBerry07/4fc9690bde762b3cd7522f1927337707 to your computer and use it in GitHub Desktop.
Form Animations
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<button class="bg-toggle">Toggle dark/light</button> | |
<form action="#" novalidate> | |
<div class="form-group has-icon fa-envelope-o"> | |
<label class="movable" for="email">Email address</label> | |
<input type="email" name="email" id="email" class="form-field required email" /> | |
<span class="error-message">Please enter a valid email address</span> | |
</div> | |
<div class="form-group has-icon fa-user-o"> | |
<label class="movable" for="name">Name</label> | |
<input type="text" name="name" id="name" class="form-field required" /> | |
<span class="error-message">This is a required field with a much longer error message to see what it's like with multiple lines</span> | |
</div> | |
<div class="form-group has-icon fa-comment-o"> | |
<label class="movable" for="comment">Comment</label> | |
<textarea name="comment" id="comment" rows="6" class="form-field required"></textarea> | |
<span class="error-message">Comment perhaps?</span> | |
</div> | |
<div class="form-group has-icon select fa-heart-o"> | |
<label class="movable" for="options">Select an option</label> | |
<select name="options" id="options" class="form-field required"> | |
<option value="" selected>Select an option</option> | |
<option value="1">This is a great option</option> | |
<option value="2">This option is cool too</option> | |
<option value="3">This option is okay I guess</option> | |
</select> | |
<span class="error-message">Select something tho...</span> | |
</div> | |
<div class="form-group has-icon select dropdown-up fa-diamond"> | |
<label class="movable" for="moreoptions">Another dropdown but up this time</label> | |
<select name="moreoptions" id="moreoptions" class="form-field required"> | |
<option value="" selected>Another dropdown but up this time</option> | |
<option value="1">How about checking what an option that's longer than one line looks like?</option> | |
<option value="2">Lorem my ipsum</option> | |
<option value="3">Me: *adds placeholder*</option> | |
<option value="4">Place: *is hold*</option> | |
</select> | |
<span class="error-message">Select something tho...</span> | |
</div> | |
<div class="form-group checkbox"> | |
<input type="checkbox" class="fa fa-check" name="news" id="news" /> | |
<label for="news">Get news updates</label> | |
</div> | |
<div class="form-group"> | |
<button type="submit" class="form-submit">Submit Form</button> | |
</div> | |
</form> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$(".form-group .form-field").on "focus change", () -> | |
unless $(this).closest(".form-group").hasClass("select") and $(this).val() is "" | |
$(this).closest(".form-group").addClass("moved") | |
return | |
.on "blur change", () -> | |
if $(this).val().trim() is "" | |
$(this).closest(".form-group").removeClass("moved") | |
return | |
.on "change keypress", () -> | |
$(this).closest(".invalid").removeClass "invalid" | |
return | |
window.emailRegex = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i; | |
$("form").on "submit", (e) -> | |
valid = true; | |
form = $(this) | |
form.find(".invalid").removeClass("invalid") | |
form.find(".required").each () -> | |
field = $(this) | |
val = field.val().trim() | |
if val is "" or (field.attr("type") is "email" and !emailRegex.test(val)) | |
valid = false; | |
field.closest(".form-group").addClass "invalid" | |
field.focus() | |
return false | |
if !valid | |
e.preventDefault() | |
else | |
alert(form.serialize()) | |
e.preventDefault() | |
return | |
$("form .error-message").on "click", () -> | |
$(this).closest(".invalid").removeClass "invalid" | |
return | |
$(".bg-toggle").on "click", () -> | |
$('body,form').toggleClass('dark') | |
return | |
if !(/Mobi/.test(navigator.userAgent)) | |
$(".form-group.select select").on "mousedown touchstart focus", (e) -> | |
e.preventDefault() | |
isOpen = $(this).siblings(".dropdown").hasClass "open" | |
$(".form-group .dropdown").removeClass "open" | |
if isOpen isnt true | |
$(this).siblings(".dropdown").addClass("open") | |
$(this).blur().siblings(".dropdown").find("a.selected").focus() | |
return | |
.each () -> | |
options = $(this).find "option" | |
dropdown = $("<ul></ul>").addClass "dropdown" | |
options.each () -> | |
optionValue = $(this).attr("value") | |
optionText = $(this).text() | |
li = $("<li></li>") | |
option = $("<a></a>").attr({"href": "#", "data-val": optionValue}).text(optionText) | |
if $(this).attr "selected" | |
option.addClass "selected" | |
option.on "click", (e) -> | |
e.preventDefault() | |
dropdown.find(".selected").removeClass("selected") | |
$(this).addClass("selected") | |
.closest(".form-group") | |
.find("select") | |
.val($(this).attr("data-val")) | |
.trigger("change") | |
dropdown.removeClass("open") | |
return | |
.on "keydown", (e) -> | |
key = if e.keyCode then e.keyCode else e.which | |
if key is 40 | |
$(this).closest("li").next("li").find("a").focus() | |
else if key is 38 | |
$(this).closest("li").prev("li").find("a").focus() | |
return | |
li.append option | |
dropdown.append li | |
$(this).closest(".form-group").append dropdown | |
return | |
$(document).on "click", (e) -> | |
unless $(e.target).closest(".form-group.select").find(".dropdown.open").length | |
$(".form-group .dropdown").removeClass "open" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@keyframes iconWiggle { | |
0% { transform: rotate(0deg) } | |
20% { transform: rotate(15deg) } | |
40% { transform: rotate(-15deg) } | |
60% { transform: rotate(15deg) } | |
80% { transform: rotate(-15deg) } | |
100% { transform: rotate(0deg) } | |
} | |
@keyframes iconPinch { | |
0% { transform: scale(1) } | |
50% { transform: scale(0.8) } | |
100% { transform: scale(1) } | |
} | |
html { | |
font-size: 14px; | |
} | |
body { | |
background: #fff; | |
color: #2b3452; | |
font-family: 'Open Sans', sans-serif; | |
transition: background-color 0.2s; | |
&.dark { | |
background-color: #2b3452; | |
} | |
} | |
form { | |
box-sizing: border-box; | |
max-width: 100%; | |
width: 420px; | |
padding: 0 15px; | |
margin: 15px auto 50px; | |
} | |
.form-group { | |
margin-top: 1.6rem; | |
position: relative; | |
min-height: 3rem; | |
line-height: 3rem; | |
&.checkbox { | |
line-height: 1.5rem; | |
min-height: 1.5rem; | |
} | |
label.movable { | |
position: absolute; | |
pointer-events: none; | |
top: 0; | |
z-index: 2; | |
height: 3rem; | |
line-height: 3rem; | |
color: darken(#d8dbe8,10%); | |
padding: 0 15px; | |
font-size: 1rem; | |
font-weight: 400; | |
transition: all 0.2s; | |
} | |
.form-field { | |
border: 1px solid darken(#d8dbe8,5%); | |
transition-property: border, box-shadow; | |
transition-duration: 0.2s; | |
-webkit-appearance: none; | |
-moz-appearance: none; | |
//firefox specific - hide select arrow | |
text-indent: 0.01px; | |
text-overflow: ""; | |
//ie specific - hide select arrow | |
&::-ms-expand { | |
display: none; | |
} | |
option { | |
color: black; | |
} | |
} | |
.form-field, .form-submit { | |
color: inherit; | |
display: block; | |
position: relative; | |
z-index: 1; | |
font-size: inherit; | |
width: 100%; | |
box-sizing: border-box; | |
border-radius: 4px; | |
background: white; | |
padding: 12px 15px; | |
min-height: 3rem; | |
&:not(textarea) { | |
height: 3rem; | |
padding: 0 15px; | |
} | |
} | |
textarea { | |
resize: vertical; | |
} | |
input[type="checkbox"] { | |
width: 16px; | |
height: 16px; | |
vertical-align: middle; | |
-webkit-appearance: none; | |
-moz-appearance: none; | |
border: 1px solid #c8ccdf; | |
line-height: 14px; | |
text-align: center; | |
border-radius: 4px; | |
margin-right: 5px; | |
color: #0a78f5; | |
font-size: 12px; | |
transition: all 0.2s; | |
background: white; | |
&::before { | |
opacity: 0; | |
transition: opacity 0.1s; | |
} | |
&:checked::before { | |
opacity: 1; | |
} | |
} | |
.form-field, input[type="checkbox"] { | |
&:focus { | |
box-shadow: 0 0 4px 3px fade(#3b93f7,20%); | |
border: 1px solid #3b93f7; | |
outline: none; | |
} | |
+ label { | |
color: darken(#d8dbe8,15%); | |
} | |
} | |
.error-message { | |
box-sizing: border-box; | |
color: white; | |
font-size: 0.8rem; | |
line-height: 1.2rem; | |
font-weight: 600; | |
position: absolute; | |
top: 100%; | |
left: 5px; | |
z-index: 3; | |
margin-top: 2px; | |
background: #e66051; | |
max-width: calc(~"100% - 10px"); | |
padding: 5px 10px 5px 30px; | |
border-radius: 4px; | |
box-shadow: 0 2px 10px fade(black,10%); | |
transition: transform 0.2s; | |
transform: scale(0); | |
transform-origin: 18px 0; | |
&::before { | |
font-family: "FontAwesome"; | |
content: "\f057"; | |
position: absolute; | |
top: 5px; | |
left: 12px; | |
cursor: pointer; | |
} | |
&::after { | |
content: " "; | |
position: absolute; | |
border: 6px solid transparent; | |
border-bottom-color: #e66051; | |
top: -12px; | |
left: 10px; | |
} | |
} | |
.form-submit { | |
background: #3b93f7; | |
color: white; | |
font-weight: 600; | |
font-size: 1.2rem; | |
border: 0; | |
transition: all 0.2s; | |
cursor: pointer; | |
&:hover { | |
background: darken(#3b93f7,10%); | |
transform: translateY(-2px); | |
} | |
&:active { | |
transform: translateY(0); | |
} | |
} | |
&.has-icon { | |
&::before { | |
font-family: "FontAwesome"; | |
position: absolute; | |
line-height: 3rem; | |
top: 0; | |
left: 0; | |
width: 3rem; | |
text-align: center; | |
z-index: 2; | |
color: darken(#d8dbe8,10%); | |
pointer-events: none; | |
transition: color 0.2s; | |
animation: none; | |
} | |
&.checkbox, .form-field, label.movable, { | |
padding-left: 3rem; | |
} | |
} | |
&.moved { | |
&::before { | |
color: #3b93f7; | |
animation: iconPinch 0.3s ease-in-out; | |
} | |
label.movable { | |
top: -1.5rem; | |
height: 1rem; | |
line-height: 1.5rem; | |
font-size: 0.8rem; | |
font-weight: 600; | |
padding-left: 0; | |
&::after { | |
content: ":"; | |
} | |
} | |
} | |
&.invalid { | |
label { | |
color: #e66051; | |
} | |
.error-message { | |
transform: scale(1); | |
} | |
&::before { | |
color: #e66051; | |
animation: iconWiggle 0.4s ease-in-out; | |
} | |
.form-field { | |
background: #fff5f5; | |
border: 1px solid #e66051; | |
&:focus { | |
box-shadow: 0 0 4px 3px fade(#e66051,20%) | |
} | |
} | |
} | |
&.select { | |
&::after { | |
content: " "; | |
position: absolute; | |
right: 10px; | |
border: 4px solid transparent; | |
border-top-color: darken(#d8dbe8,10%); | |
top: 50%; | |
margin-top: -2px; | |
z-index: 2; | |
transition: border-top-color 0.2s; | |
} | |
.form-field { | |
color: white; | |
padding-right: 30px; | |
} | |
&.moved .form-field { | |
color: inherit; | |
} | |
&.invalid::after { | |
border-top-color: #e66051; | |
} | |
.dropdown { | |
position: absolute; | |
z-index: 4; | |
top: 100%; | |
margin-top: 2px; | |
left: 5px; | |
right: 5px; | |
background: #d8dbe8; | |
padding: 0; | |
border-radius: 4px; | |
transform-origin: 50% 0; | |
transform: scale(0); | |
transition: transform 0.2s; | |
box-shadow: 0 2px 10px fade(black,10%); | |
padding: 5px 0; | |
font-size: 0.9rem; | |
line-height: 1.2rem; | |
&::before { | |
content: " "; | |
position: absolute; | |
top: -12px; | |
border: 6px solid transparent; | |
border-bottom-color: #d8dbe8; | |
left: 50%; | |
margin-left: -6px; | |
} | |
&.open { | |
transform: scale(1); | |
} | |
li { | |
list-style: none; | |
a { | |
display: block; | |
padding: 10px 30px; | |
text-decoration: none; | |
color: #555; | |
transition: background-color 0.2s; | |
position: relative; | |
&:hover, &:focus { | |
background: fade(white,30%); | |
outline: none; | |
} | |
&.selected { | |
&::before { | |
content: " "; | |
position: absolute; | |
left: 15px; | |
top: 50%; | |
margin-top: -5px; | |
width: 4px; | |
height: 8px; | |
border: solid #3b93f7; | |
border-width: 0 1px 1px 0; | |
transform: rotate(45deg); | |
} | |
} | |
} | |
} | |
} | |
&.dropdown-up .dropdown { | |
top: auto; | |
bottom: 100%; | |
margin-bottom: 2px; | |
transform-origin: 50% 100%; | |
&::before { | |
top: auto; | |
bottom: -12px; | |
border-top-color: #d8dbe8; | |
border-bottom-color: transparent; | |
} | |
} | |
} | |
} | |
form.dark { | |
.form-group { | |
&.moved label { | |
color: white; | |
} | |
&.moved.invalid label { | |
color: #f58d81; | |
} | |
.form-submit, .form-field:not(:focus) { | |
box-shadow: 0 2px 10px fade(black,10%); | |
} | |
.form-field, input[type="checkbox"] { | |
border: 1px solid white; | |
} | |
input[type="checkbox"] + label { | |
color: white; | |
} | |
} | |
} | |
.bg-toggle { | |
background: #fff; | |
border: 1px solid #666; | |
color: #666; | |
font-weight: 600; | |
border-radius: 4px; | |
margin: 15px; | |
font-size: 12px; | |
padding: 3px 5px; | |
cursor: pointer; | |
transition: all 0.15s; | |
opacity: 0.65; | |
.dark & { | |
background: none; | |
border-color: white; | |
color: white; | |
} | |
&:hover { | |
transform: translateY(-1px); | |
opacity: 1; | |
} | |
&:active { | |
transform: translateY(0); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,600" rel="stylesheet" /> | |
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" /> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment