#box-shadow
Explore tagged Tumblr posts
Text
How to Create Multi-Step Forms With Vanilla JavaScript and CSS
New Post has been published on https://thedigitalinsider.com/how-to-create-multi-step-forms-with-vanilla-javascript-and-css/
How to Create Multi-Step Forms With Vanilla JavaScript and CSS
Multi-step forms are a good choice when your form is large and has many controls. No one wants to scroll through a super-long form on a mobile device. By grouping controls on a screen-by-screen basis, we can improve the experience of filling out long, complex forms.
But when was the last time you developed a multi-step form? Does that even sound fun to you? Thereâs so much to think about and so many moving pieces that need to be managed that I wouldnât blame you for resorting to a form library or even some type of form widget that handles it all for you.
But doing it by hand can be a good exercise and a great way to polish the basics. Iâll show you how I built my first multi-step form, and I hope youâll not only see how approachable it can be but maybe even spot areas to make my work even better.
Weâll walk through the structure together. Weâll build a job application, which I think many of us can relate to these recent days. Iâll scaffold the baseline HTML, CSS, and JavaScript first, and then weâll look at considerations for accessibility and validation.
Iâve created a GitHub repo for the final code if you want to refer to it along the way.
The structure of a multi-step form
Our job application form has four sections, the last of which is a summary view, where we show the user all their answers before they submit them. To achieve this, we divide the HTML into four sections, each identified with an ID, and add navigation at the bottom of the page. Iâll give you that baseline HTML in the next section.
Navigating the user to move through sections means weâll also include a visual indicator for what step they are at and how many steps are left. This indicator can be a simple dynamic text that updates according to the active step or a fancier progress bar type of indicator. Weâll do the former to keep things simple and focused on the multi-step nature of the form.,
The structure and basic styles
Weâll focus more on the logic, but I will provide the code snippets and a link to the complete code at the end.
Letâs start by creating a folder to hold our pages. Then, create an index.html file and paste the following into it:
Open HTML
<form id="myForm"> <section class="group-one" id="one"> <div class="form-group"> <div class="form-control"> <label for="name">Name <span style="color: red;">*</span></label> <input type="text" id="name" name="name" placeholder="Enter your name"> </div> <div class="form-control"> <label for="idNum">ID number <span style="color: red;">*</span></label> <input type="number" id="idNum" name="idNum" placeholder="Enter your ID number"> </div> </div> <div class="form-group"> <div class="form-control"> <label for="email">Email <span style="color: red;">*</span></label> <input type="email" id="email" name="email" placeholder="Enter your email"> </div> <div class="form-control"> <label for="birthdate">Date of Birth <span style="color: red;">*</span></label> <input type="date" id="birthdate" name="birthdate" max="2006-10-01" min="1924-01-01"> </div> </div> </section> <section class="group-two" id="two"> <div class="form-control"> <label for="document">Upload CV <span style="color: red;">*</span></label> <input type="file" name="document" id="document"> </div> <div class="form-control"> <label for="department">Department <span style="color: red;">*</span></label> <select id="department" name="department"> <option value="">Select a department</option> <option value="hr">Human Resources</option> <option value="it">Information Technology</option> <option value="finance">Finance</option> </select> </div> </section> <section class="group-three" id="three"> <div class="form-control"> <label for="skills">Skills (Optional)</label> <textarea id="skills" name="skills" rows="4" placeholder="Enter your skills"></textarea> </div> <div class="form-control"> <input type="checkbox" name="terms" id="terms"> <label for="terms">I agree to the terms and conditions <span style="color: red;">*</span></label> </div> <button id="btn" type="submit">Confirm and Submit</button> </section> <div class="arrows"> <button type="button" id="navLeft">Previous</button> <span id="stepInfo"></span> <button type="button" id="navRight">Next</button> </div> </form> <script src="script.js"></script>
Looking at the code, you can see three sections and the navigation group. The sections contain form inputs and no native form validation. This is to give us better control of displaying the error messages because native form validation is only triggered when you click the submit button.
Next, create a styles.css file and paste this into it:
Open base styles
:root --primary-color: #8c852a; --secondary-color: #858034; body font-family: sans-serif; line-height: 1.4; margin: 0 auto; padding: 20px; background-color: #f4f4f4; max-width: 600px; h1 text-align: center; form background: #fff; padding: 40px; border-radius: 5px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); display: flex; flex-direction: column; .form-group display: flex; gap: 7%; .form-group > div width: 100%; input:not([type="checkbox"]), select, textarea width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px; .form-control margin-bottom: 15px; button display: block; width: 100%; padding: 10px; color: white; background-color: var(--primary-color); border: none; border-radius: 4px; cursor: pointer; font-size: 16px; button:hover background-color: var(--secondary-color); .group-two, .group-three display: none; .arrows display: flex; justify-content: space-between align-items: center; margin-top: 10px; #navLeft, #navRight width: fit-content; @media screen and (max-width: 600px) .form-group flex-direction: column;
Open up the HTML file in the browser, and you should get something like the two-column layout in the following screenshot, complete with the current page indicator and navigation.
Adding functionality with vanilla JavaScript
Now, create a script.js file in the same directory as the HTML and CSS files and paste the following JavaScript into it:
Open base scripts
const stepInfo = document.getElementById("stepInfo"); const navLeft = document.getElementById("navLeft"); const navRight = document.getElementById("navRight"); const form = document.getElementById("myForm"); const formSteps = ["one", "two", "three"]; let currentStep = 0; function updateStepVisibility() formSteps.forEach((step) => document.getElementById(step).style.display = "none"; ); document.getElementById(formSteps[currentStep]).style.display = "block"; stepInfo.textContent = `Step $currentStep + 1 of $formSteps.length`; navLeft.style.display = currentStep === 0 ? "none" : "block"; navRight.style.display = currentStep === formSteps.length - 1 ? "none" : "block"; document.addEventListener("DOMContentLoaded", () => navLeft.style.display = "none"; updateStepVisibility(); navRight.addEventListener("click", () => if (currentStep < formSteps.length - 1) currentStep++; updateStepVisibility(); ); navLeft.addEventListener("click", () => if (currentStep > 0) currentStep--; updateStepVisibility(); ); );
This script defines a method that shows and hides the section depending on the formStep values that correspond to the IDs of the form sections. It updates stepInfo with the current active section of the form. This dynamic text acts as a progress indicator to the user.
It then adds logic that waits for the page to load and click events to the navigation buttons to enable cycling through the different form sections. If you refresh your page, you will see that the multi-step form works as expected.
Multi-step form navigation
Letâs dive deeper into what the Javascript code above is doing. In the updateStepVisibility() function, we first hide all the sections to have a clean slate:
formSteps.forEach((step) => document.getElementById(step).style.display = "none"; );
Then, we show the currently active section:
document.getElementById(formSteps[currentStep]).style.display = "block";`
Next, we update the text that indicators progress through the form:
stepInfo.textContent = `Step $currentStep + 1 of $formSteps.length`;
Finally, we hide the Previous button if we are at the first step and hide the Next button if we are at the last section:
navLeft.style.display = currentStep === 0 ? "none" : "block"; navRight.style.display = currentStep === formSteps.length - 1 ? "none" : "block";
Letâs look at what happens when the page loads. We first hide the Previous button as the form loads on the first section:
document.addEventListener("DOMContentLoaded", () => navLeft.style.display = "none"; updateStepVisibility();
Then we grab the Next button and add a click event that conditionally increments the current step count and then calls the updateStepVisibility() function, which then updates the new section to be displayed:
navRight.addEventListener("click", () => if (currentStep < formSteps.length - 1) currentStep++; updateStepVisibility(); );
Finally, we grab the Previous button and do the same thing but in reverse. Here, we are conditionally decrementing the step count and calling the updateStepVisibility():
navLeft.addEventListener("click", () => if (currentStep > 0) currentStep--; updateStepVisibility(); );
Handling errors
Have you ever spent a good 10+ minutes filling out a form only to submit it and get vague errors telling you to correct this and that? I prefer it when a form tells me right away that somethingâs amiss so that I can correct it before I ever get to the Submit button. Thatâs what weâll do in our form.
Our principle is to clearly indicate which controls have errors and give meaningful error messages. Clear errors as the user takes necessary actions. Letâs add some validation to our form. First, letâs grab the necessary input elements and add this to the existing ones:
const nameInput = document.getElementById("name"); const idNumInput = document.getElementById("idNum"); const emailInput = document.getElementById("email"); const birthdateInput = document.getElementById("birthdate") const documentInput = document.getElementById("document"); const departmentInput = document.getElementById("department"); const termsCheckbox = document.getElementById("terms"); const skillsInput = document.getElementById("skills");
Then, add a function to validate the steps:
Open validation script
function validateStep(step)
Here, we check if each required input has some value and if the email input has a valid input. Then, we set the isValid boolean accordingly. We also call a showError() function, which we havenât defined yet.
Paste this code above the validateStep() function:
function showError(input, message) const formControl = input.parentElement; const errorSpan = formControl.querySelector(".error-message"); input.classList.add("error"); errorSpan.textContent = message;
Now, add the following styles to the stylesheet:
Open validation styles
input:focus, select:focus, textarea:focus outline: .5px solid var(--primary-color); input.error, select.error, textarea.error outline: .5px solid red; .error-message font-size: x-small; color: red; display: block; margin-top: 2px; .arrows color: var(--primary-color); font-size: 18px; font-weight: 900; #navLeft, #navRight display: flex; align-items: center; gap: 10px; #stepInfo color: var(--primary-color);
If you refresh the form, you will see that the buttons do not take you to the next section till the inputs are considered valid:
Finally, we want to add real-time error handling so that the errors go away when the user starts inputting the correct information. Add this function below the validateStep() function:
Open real-time validation script
function setupRealtimeValidation() nameInput.addEventListener("input", () => if (nameInput.value.trim() !== "") clearError(nameInput); ); idNumInput.addEventListener("input", () => if (idNumInput.value.trim() !== "") clearError(idNumInput); ); emailInput.addEventListener("input", () => if (emailInput.validity.valid) clearError(emailInput); ); birthdateInput.addEventListener("change", () => if (birthdateInput.value !== "") clearError(birthdateInput); ); documentInput.addEventListener("change", () => if (documentInput.files[0]) clearError(documentInput); ); departmentInput.addEventListener("change", () => if (departmentInput.value !== "") clearError(departmentInput); ); termsCheckbox.addEventListener("change", () => if (termsCheckbox.checked) clearError(termsCheckbox); );
This function clears the errors if the input is no longer invalid by listening to input and change events then calling a function to clear the errors. Paste the clearError() function below the showError() one:
function clearError(input) const formControl = input.parentElement; const errorSpan = formControl.querySelector(".error-message"); input.classList.remove("error"); errorSpan.textContent = "";
And now the errors clear when the user types in the correct value:
The multi-step form now handles errors gracefully. If you do decide to keep the errors till the end of the form, then at the very least, jump the user back to the erroring form control and show some indication of how many errors they need to fix.
Handling form submission
In a multi-step form, it is valuable to show the user a summary of all their answers at the end before they submit and to offer them an option to edit their answers if necessary. The person canât see the previous steps without navigating backward, so showing a summary at the last step gives assurance and a chance to correct any mistakes.
Letâs add a fourth section to the markup to hold this summary view and move the submit button within it. Paste this just below the third section in index.html:
Open HTML
<section class="group-four" id="four"> <div class="summary-section"> <p>Name: </p> <p id="name-val"></p> <button type="button" class="edit-btn" id="name-edit"> <span>â</span> <span>Edit</span> </button> </div> <div class="summary-section"> <p>ID Number: </p> <p id="id-val"></p> <button type="button" class="edit-btn" id="id-edit"> <span>â</span> <span>Edit</span> </button> </div> <div class="summary-section"> <p>Email: </p> <p id="email-val"></p> <button type="button" class="edit-btn" id="email-edit"> <span>â</span> <span>Edit</span> </button> </div> <div class="summary-section"> <p>Date of Birth: </p> <p id="bd-val"></p> <button type="button" class="edit-btn" id="bd-edit"> <span>â</span> <span>Edit</span> </button> </div> <div class="summary-section"> <p>CV/Resume: </p> <p id="cv-val"></p> <button type="button" class="edit-btn" id="cv-edit"> <span>â</span> <span>Edit</span> </button> </div> <div class="summary-section"> <p>Department: </p> <p id="dept-val"></p> <button type="button" class="edit-btn" id="dept-edit"> <span>â</span> <span>Edit</span> </button> </div> <div class="summary-section"> <p>Skills: </p> <p id="skills-val"></p> <button type="button" class="edit-btn" id="skills-edit"> <span>â</span> <span>Edit</span> </button> </div> <button id="btn" type="submit">Confirm and Submit</button> </section>
Then update the formStep in your Javascript to read:
const formSteps = ["one", "two", "three", "four"];
Finally, add the following classes to styles.css:
.summary-section display: flex; align-items: center; gap: 10px; .summary-section p:first-child width: 30%; flex-shrink: 0; border-right: 1px solid var(--secondary-color); .summary-section p:nth-child(2) width: 45%; flex-shrink: 0; padding-left: 10px; .edit-btn width: 25%; margin-left: auto; background-color: transparent; color: var(--primary-color); border: .7px solid var(--primary-color); border-radius: 5px; padding: 5px; .edit-btn:hover border: 2px solid var(--primary-color); font-weight: bolder; background-color: transparent;
Now, add the following to the top of the script.js file where the other consts are:
const nameVal = document.getElementById("name-val"); const idVal = document.getElementById("id-val"); const emailVal = document.getElementById("email-val"); const bdVal = document.getElementById("bd-val") const cvVal = document.getElementById("cv-val"); const deptVal = document.getElementById("dept-val"); const skillsVal = document.getElementById("skills-val"); const editButtons = "name-edit": 0, "id-edit": 0, "email-edit": 0, "bd-edit": 0, "cv-edit": 1, "dept-edit": 1, "skills-edit": 2 ;
Then add this function in scripts.js:
function updateSummaryValues() nameVal.textContent = nameInput.value; idVal.textContent = idNumInput.value; emailVal.textContent = emailInput.value; bdVal.textContent = birthdateInput.value; const fileName = documentInput.files[0]?.name; if (fileName) const extension = fileName.split(".").pop(); const baseName = fileName.split(".")[0]; const truncatedName = baseName.length > 10 ? baseName.substring(0, 10) + "..." : baseName; cvVal.textContent = `$truncatedName.$extension`; else cvVal.textContent = "No file selected"; deptVal.textContent = departmentInput.value; skillsVal.textContent = skillsInput.value || "No skills submitted"; }
This dynamically inserts the input values into the summary section of the form, truncates the file names, and offers a fallback text for the input that was not required.
Then update the updateStepVisibility() function to call the new function:
function updateStepVisibility() formSteps.forEach((step) => document.getElementById(step).style.display = "none"; ); document.getElementById(formSteps[currentStep]).style.display = "block"; stepInfo.textContent = `Step $currentStep + 1 of $formSteps.length`; if (currentStep === 3) updateSummaryValues(); navLeft.style.display = currentStep === 0 ? "none" : "block"; navRight.style.display = currentStep === formSteps.length - 1 ? "none" : "block";
Finally, add this to the DOMContentLoaded event listener:
Object.keys(editButtons).forEach((buttonId) => const button = document.getElementById(buttonId); button.addEventListener("click", (e) => currentStep = editButtons[buttonId]; updateStepVisibility(); ); );
Running the form, you should see that the summary section shows all the inputted values and allows the user to edit any before submitting the information:
And now, we can submit our form:
form.addEventListener("submit", (e) => e.preventDefault(); if (validateStep(2)) alert("Form submitted successfully!"); form.reset(); currentFormStep = 0; updateStepVisibility(); );
Our multi-step form now allows the user to edit and see all the information they provide before submitting it.
Accessibility tips
Making multi-step forms accessible starts with the basics: using semantic HTML. This is half the battle. It is closely followed by using appropriate form labels.
Other ways to make forms more accessible include giving enough room to elements that must be clicked on small screens and giving meaningful descriptions to the form navigation and progress indicators.
Offering feedback to the user is an important part of it; itâs not great to auto-dismiss user feedback after a certain amount of time but to allow the user to dismiss it themselves. Paying attention to contrast and font choice is important, too, as they both affect how readable your form is.
Letâs make the following adjustments to the markup for more technical accessibility:
Add aria-required="true" to all inputs except the skills one. This lets screen readers know the fields are required without relying on native validation.
Add role="alert" to the error spans. This helps screen readers know to give it importance when the input is in an error state.
Add role="status" aria-live="polite" to the .stepInfo. This will help screen readers understand that the step info keeps tabs on a state, and the aria-live being set to polite indicates that should the value change, it does not need to immediately announce it.
In the script file, replace the showError() and clearError() functions with the following:
function showError(input, message) const formControl = input.parentElement; const errorSpan = formControl.querySelector(".error-message"); input.classList.add("error"); input.setAttribute("aria-invalid", "true"); input.setAttribute("aria-describedby", errorSpan.id); errorSpan.textContent = message; function clearError(input) const formControl = input.parentElement; const errorSpan = formControl.querySelector(".error-message"); input.classList.remove("error"); input.removeAttribute("aria-invalid"); input.removeAttribute("aria-describedby"); errorSpan.textContent = "";
Here, we programmatically add and remove attributes that explicitly tie the input with its error span and show that it is in an invalid state.
Finally, letâs add focus on the first input of every section; add the following code to the end of the updateStepVisibility() function:
const currentStepElement = document.getElementById(formSteps[currentStep]); const firstInput = currentStepElement.querySelector( "input, select, textarea" ); if (firstInput) firstInput.focus();
And with that, the multi-step form is much more accessible.
Conclusion
There we go, a four-part multi-step form for a job application! As I said at the top of this article, thereâs a lot to juggle â so much so that I wouldnât fault you for looking for an out-of-the-box solution.
But if you have to hand-roll a multi-step form, hopefully now you see itâs not a death sentence. Thereâs a happy path that gets you there, complete with navigation and validation, without turning away from good, accessible practices.
And this is just how I approached it! Again, I took this on as a personal challenge to see how far I could get, and Iâm pretty happy with it. But Iâd love to know if you see additional opportunities to make this even more mindful of the user experience and considerate of accessibility.
References
Here are some relevant links I referred to when writing this article:
How to Structure a Web Form (MDN)
Multi-page Forms (W3C.org)
Create accessible forms (A11y Project)
#:not#Accessibility#ADD#aria#Article#Articles#attention#attributes#background#border-radius#box#box-shadow#browser#buttons#challenge#change#classes#code#Color#content#CSS#CV#dept#direction#display#email#error handling#event#Events#Exercise
3 notes
·
View notes
Text

10K notes
·
View notes
Text
CSS3: Revolucionando el Diseño Web en Alicante y la Comunidad Valenciana
Las Nuevas Reglas: CSS3 se Vuelve Loco CSS3 ha traĂdo consigo una serie de propiedades y caracterĂsticas que han revolucionado la forma en que diseñamos y animamos nuestras pĂĄginas web. Estas nuevas herramientas nos permiten crear interfaces de usuario mĂĄs atractivas, interactivas y personalizadas. Exploremos algunas de las propiedades CSS3 mĂĄs populares y cĂłmo se estĂĄn utilizando en Alicante yâŠ
#@font-face#border-image#border-radius#box-shadow#gradient#hsla#outline#rgba#rotate#scale#skew#text-shadow#transform#transition#translate
0 notes
Text
I wish gay people were real
#I got lazy with the background and such but yk#Iâm kinda proud of it#it isnât a lot but yea!#sonadow#my art#mossy art#mossy-box art#sonic the hedgehog#shadow the hedgehog#shadonic#sonic x shadow generations#I added a scarf bc itâs jolly season idk#a fic inspired me to draw this#artists on tumblr#sth#sth fanart#ignore how I forgot Sonics other hand itâs rough out here
6K notes
·
View notes
Note
https://www.tumblr.com/jackie-mae/775978232280383488/it-was-jelly-fish-wishes-who-commented-about-pure?source=share
Great now I need to see the gentle rocking in action because now I can't get it out of my head that when pure vanilla starts growing more attatched to him...instead of violently shacking the hat, he just starts gently rocking it to either get shadow milk to calm down or straight up fall asleep lol...
Main weapon against lies at first: rapid shaking!
Main weapon against lies once pure vanilla catches more feelings and affection for shadow milk: calm down rocking/nap time!
Can already slightly imagine:
Shadow milk: *lies or is getting fussy or something*
Pure vanilla: oop! Looks like someone needs nap time/oop, looks like somebody needs a nap.
Shadow milk: wait-

You get me,
and to add to that I think PV instead of comforting Smilk like a baby but instead comforting him like his sheep (Completely oblivious to the well-known fact he treats his sheep like his own children) Is also just as fluffy and/or hilarious.
PV is so genuine and sweet it makes me want to vomit- me but also Smilk at some point
#my art#crk au#cookie run kingdom#pure vanilla crk#shadow milk crk#hatsmilkau#doodles#ask box spring cleaning
2K notes
·
View notes
Text




Teaser time cuz Iâm so close to 30k on TikTok itâs insane
#Father/Mother is feeling generous#eat the damn scraps while I finish cooking đ
đŸ#ask box bout to reopen for a whole new reason lolll#sonic au#sonic prime#sonic the hedgehog#sonic prime au#shadow the hedgehog#sonadow prime#jase doodles#sonadow#sonic prime fragmented#sonic prime fragmented asks#ask sonic coming soon???
2K notes
·
View notes
Note
hey.... I would like a Deceit Trio+ Reader who has N(Murder Dronesđ) personality. Looks like a cinnamon roll, would kill you. (Gelp)
âËâșâ§â✠DECEITFUL DROMEDA âŸââ§âșËâ
âŸâ Summary: A Compilation of Headcannons Featuring The Deceit Trio X Reader Who Looks Like A Sweet Person, But Would Actually Kill Others
âŸâ Character(s): Black Sapphire Cookie (Cookie Run), Candy Apple Cookie (Cookie Run), Shadow Milk Cookie (Cookie Run)
âŸâ Genre: Headcannons, SFW
âŸâ Warning(s): None - Completely Safe!
ïżœïżœ Shadow Milk Cookie figured it out almost instantly. Oh, how fun! A darling Cookie with honeyed words and a giggle sweet enough to rot teethâyet, beneath that, a predator in powdered sugar. âAhh, youâre just like me,â he croons, eyes glinting like shattered glass. He sees through your deception, but does he mind? Oh, no. If anything, he revels in it. How delightful it is to spin a tale where no one suspects the wolf dressed in frosting!
â¶ âYouâre dangerous. I like that,â Black Sapphire Cookie hums, voice laced with amusement as he idly spins his microphone between his fingers. He doesnât care for virtue, honesty, or justiceâhe only cares about a good show. And you? Youâre a walking plot twist, the kind that leaves audiences gasping. Heâll whisper rumors about you just to see how the world reacts. The best part? No one will believe a single one. Who would suspect such a sweetheart?
â¶ Candy Apple Cookie adores you. âYouâre like a candy apple with a razor blade inside! Hee hee! Just like me!â she sings, clinging to your arm. She drags you into her mischief, delighting in the way you smile so kindly before striking without mercy. âBetcha taste even sweeter with a little bit of deception!â she teases, licking her lips. Sheâs convinced youâre soulmatesâtwins in trickery.
â¶ Shadow Milk watches you like a cat with a trapped bird. Oh, the duality of your nature intrigues him! A lie within a lie, a darling assassin wrapped in bows and pleasantries. âTell me, little one,â he muses, leaning in with a lazy smirk, âdo you ever tire of pretending?â He already knows the answer, but he loves watching you act. After all, a performer canât stop the show.
â¶ The best rumors are the ones no one believes. And you? Youâre the juiciest secret Black Sapphire has ever uncovered. He enjoys dropping hints, little breadcrumbs leading nowhere. âDid you hear? The sweetest Cookie in town is hiding something deliciously wickedâŠâ But of course, who would take Black Sapphire Cookie seriously? Lies are his trade, and the best lies are the ones dressed as jokes.
â¶ âYou donât have to pretend around me, you know,â Candy Apple chirps, eyes twinkling with something unreadable. Sheâs peeled back the sugary layers of your act, and she loves whatâs underneath. âItâs sooo fun watching you work! Youâre like a surprise inside a candy boxâexcept, oopsie! Someone might lose a finger!â She adores playing your shadow, watching you charm others before turning the tables.
â¶ Your deception is artful, elegant, nearly as beautiful as Shadow Milkâs own. He finds himself testing you, toying with you, tempting you. How far will you go? How deep do your secrets run? âOh, what a wonderful, wicked little thing you are,â he coos, voice dripping with amusement. Youâre one of his favorite storiesâso, so deliciously twisted.
â¶ âYouâre unpredictable. That makes you dangerous.â Black Sapphireâs usual script is built on knowing the outcome, but you? You throw his rhythm off just enough to make him interested. Black Sapphire Cookie enjoys control, but heâs willing to let you take the stage. Just once. Just to see how youâll perform. And if you impress him? Oh, he might just rewrite the whole show for you.
â¶ âLetâs do something fun,â Candy Apple whispers, dragging you along with gleeful eyes. âSomething really sweet. Really sticky.â She giggles, twirling around you as if she doesnât notice the way your eyes gleam when you smile. The two of you are chaos incarnate, a pretty little disaster wrapped in ribbons and grins. Oh, the world has no idea whatâs coming.
â¶ Shadow Milkâs hands rest over yours, leading you in a slow, taunting waltz. âI wonder,â he muses, his tone lilting, âwhen will the mask slip?â He dips you low, watching the way you refuse to falter. âOr⊠do you even have a real face beneath it?â His laughter is soft, intoxicating, and yetâhe knows. The best performers never reveal the truth.
#imagine blog#imagine#ask blog#writers on tumblr#headcanon#asks open#ask box open#anon ask#thanks anon!#cookie run#cookie run x you#cookie run x reader#cookie run kingdom#cookie run kingdom x reader#cookie run kingdom x you#shadow milk cookie#shadow milk cookie x reader#shadow milk#shadow milk x reader#smc#smc x reader#smc crk#sm cookie#black sapphire cookie#black sapphire crk#black sapphire x reader#candy apple cookie#candy apple crk#candy apple cookie x reader#cr
563 notes
·
View notes
Text
i feel like whitaker just⊠doesnât yell. like he can obviously yell when heâs scared or itâs like necessary but he just doesnât really raise his voice. if heâs frustrated he just grits his teeth, sighs through his nose, and carries on.
santos â because she is the way she is (and i love her for it) â keeps trying to get him to break. it unnerves her how he just doesnât seem to get mad at her. oh he definitely gets annoyed and exhausted, but he doesnât raise his voice. when she wonât stop kicking him in the ass when heâs fixing the clogged sink drain he just⊠lets her do it. if sheâs being lazy and wants some ice cream from the freezer but doesnât want to get up she only has to whine for a few minutes before he groans and gets it for her.
sheâs trying to see his boundaries. to see how far she can push until he proves that heâs just like every other man sheâs met and the fact that he wonât fold irks the shit out of her. idk i donât think theyâd ever really talk about it, but whitaker is a smart cookie and would probably figure out what sheâs trying to do a few months in. heâd probably casually drop that his older brothers yelled at him all the time and then his poor mom would yell herself hoarse trying to get them to quit and oh here comes his dad yelling for everyone to shut the hell up. so heâs just always been quiet. quiet little dennis who once walked on a broken ankle for a few days because he didnât wanna bother anyone.
and santos learns to live with that. to live comfortably with a guy who wonât scream at her or hurt her even when he gets mad at her. she learns to relax. to stop waiting for the other shoe to drop.
#the pitt#dennis whitaker#trinity santos#idk i feel like they will help heal each other#little black cat and her terrier bestie#she also 100% shadow boxes him#poor dude is just tryna make some eggs and she wonât stop faking him out
800 notes
·
View notes
Note
Maybe- simulating cuddles with disembodied Shmilk? Like he wants affection before his body is ready
-đ
Something, something time goes by waaaayyy too quickly for mortals and he's technically a ghost so he can't even cuddle when he wants too :[
#yea im starting to post again with something sad. what of it. i like sad things.#anywho this made me think about like. if sm likes you during the time his a âghostâ then it probably feels like hes not truely making use of#the little time alive you have if he cant like. be physically affectionate and annoying [in a loving way]#of course i mean little time by his standards. hes immortal after all#also omg this is a verry good ask but also its been rotting in my box -.-u#so sorry#cookie run kingdom x reader#cookie run x reader#shadow milk x reader#ohhh its been way too long. i feel nervous putting my art in the x reader tag now o.ou
403 notes
·
View notes
Note
could you draw Shadow with Maria? please
I didn't feel like painting, so here u got some sketches, hope it's enough đŹđ
#sonic the hedgehog#sonic fanart#shadow the hedgehog#sth fanart#sth#sonadow#maria robotnik#comic page#light angst#ask box
543 notes
·
View notes
Text



Shadow fans,,,, how are we possibly still alive right now like this is absolutely insane
#ALL THIS FOOD????#so funny tho movie shadow leaked on a popcorn bucket and then a toy box#just release the trailer guys câmon#ANYWAY SONIC X SHADOW GENERATIONS I AM LOSING MY MIND#THE POSTER#SONIC BATTLE ACKNOWLEDGMENT????#LOOK AT MARIA#OMEGA AND ROUGE????#TEAM DARK COMEBACK???#***THREE*** ANIMATED PROLOGUE EPISODES???#I AM GOING INSANE#YEAR OF SHADOW 2024 REIGNS SUPREME#WE ARE EATING THESE LAST FEW MONTHS LETS GO BRO#sonic the hedgehog#shadow the hedgehog#sonic x shadow generations#sonic x shadow generations dark beginnings#sonic movie#sonic movie 3#year of shadow
1K notes
·
View notes
Text
Weekly News for Designers â 727 - Fixing CLS Problems, CSS One-Line Upgrades, Future Roles for Designers
New Post has been published on https://thedigitalinsider.com/weekly-news-for-designers-%e2%84%96-727-fixing-cls-problems-css-one-line-upgrades-future-roles-for-designers/
Weekly News for Designers â 727 - Fixing CLS Problems, CSS One-Line Upgrades, Future Roles for Designers
Happy Birthday, Macintosh Forty years ago, Apple introduced the world to the Macintosh computer.
Free Instagram Story Templates A collection of Instagram Story templates for Photoshop, Figma, Sketch, After Effects, Premiere Pro, and Final Cut Pro.
12 Modern CSS One-Line Upgrades Learn about the CSS properties to enhance your projects, reduce technical debt, eliminate JavaScript, and improve the UX.
The Diagram that Shows the Value of Great UX
Fading Content Using Transparent Gradients in CSS Here are two methods for achieving text content fading with CSS. One uses mask-image and the other background-clip.
Top Logo Stinger Premiere Pro Templates We share a collection of logo stinger templates for Premiere Pro that stand out with their style, functionality, and ease of use.
Five Future Roles for Designers Jorge Arango shares five possible future careers for designers in our now AI-driven world.
CSS Blurry Shimmer Effect Learn how to create a CSS blurring effect, but not with box-shadow.
The CSS Snippets Every Developer Should Know Discover the CSS snippets that every front-end developer should know about in 2024.
Whatâs the Environmental Impact of Your Website? Eric examines the relationship between the web and the planet and shows how to measure your websiteâs impact.
Git and GitHub Essentials If youâre new to Git or GitHub, this extensive beginnerâs guide of the most common commands is for you.
Fixing Cumulative Layout Shift Problems
The Most Underused CSS Media Queries: hover & any-hover Learn how to use the hover and any-hover media queries for responsive design and better experiences on all devices.
Improve Your Logo Design Skills Melinda Livsey shares how she improved her logo design skills by studying the work of Paul Rand and Saul Bass.
#2024#After Effects#ai#amp#apple#background#background-clip#bass#birthday#box#box-shadow#Careers#computer#content#CSS#CSS Snippets#Design#Designer News#designers#Developer#devices#effects#Environmental#environmental impact#figma#Future#git#github#gradients#hover
2 notes
·
View notes
Text




HERES THE PART 2 @cyucya
It was too long to put into the last part but I wanted to share anyways cause gosh I love them their so silly
Continuation of this comic with Skylar-Chilli
Sonic Masterpost
#yes he is indeed jealous LMAO#but itâs ok XD#and Maria is a horrible artist LMAO but they love them cause they make them laugh#sonic has a box of them somewhere he takes out once in a while to embarrass Maria >:D#hehehe#sonic franchise#sonic the hedgehog#shadow the hedgehog#sonic fanart#sonadow fam au#sonadow
369 notes
·
View notes
Text









Just posting my upcycled sculptures again.
550 notes
·
View notes
Text
First ship of the day ÊâąáŽ„âąÊ Teddy Ghost đ»
#hachi art#danny phantom#dash baxter#teddy ghost#okay funny stories i actually got request for teddy ghost every time i open the ship dock#but everytime is the ship turn it ask got eaten by tumblr ask box or#get banish to shadow realm by ask bot overloading my ask box
920 notes
·
View notes