Skip to content

Instantly share code, notes, and snippets.

@LaunchedBerry07
Created August 24, 2022 06:12
Show Gist options
  • Save LaunchedBerry07/4fc9690bde762b3cd7522f1927337707 to your computer and use it in GitHub Desktop.
Save LaunchedBerry07/4fc9690bde762b3cd7522f1927337707 to your computer and use it in GitHub Desktop.
Form Animations
<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>
$(".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"
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
@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);
}
}
<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