- Published on
Learn How To Build A Quick Popover Feedback With Tailwind CSS Like an Expert

- What is Tailwind CSS?
- The description of Quick Popover Feedback ui component
- Why use Tailwind CSS to build a Quick Popover Feedback ui component?
- The preview of Quick Popover Feedback ui component
- The source code of Quick Popover Feedback ui component
- How to build a Quick Popover Feedback with Tailwind CSS?
- Install tailwind css of verion 2.1.0
- All the unility class needed to build a Quick Popover Feedback component
- 49 steps to build a Quick Popover Feedback component with Tailwind CSS
- Conclusion
What is Tailwind CSS?
Tailwind CSS is a utility-first CSS framework that focuses on creating personalized user interfaces quickly. It can gives you all the building blocks you are able to create personalized designs without having to fight to override irritating opinionated styles. Also, Tailwind CSS is a highly configurable, low-level CSS framework.
The description of Quick Popover Feedback ui component
Vercel style quick popover feedback with working form with web3forms
Why use Tailwind CSS to build a Quick Popover Feedback ui component?
- It can make the building process of Quick Popover Feedback ui component faster and more easily.
- Enables building complex responsive layouts and components freely.
- Minimum lines of CSS code in Quick Popover Feedback component file.
The preview of Quick Popover Feedback ui component
Free download of the Quick Popover Feedback's source code
The source code of Quick Popover Feedback ui component
<!--
=======================================================================
Name : Quick Popover Feedback
Author : Surjith S M
Twitter : @surjithctly
Get more components here 👉 https://web3templates.com/components
Copyright © 2021
=======================================================================
-->
<style>
input[type="radio"]:checked+label {
/* @apply ring-1 ring-indigo-400 border-indigo-400; */
--tw-border-opacity: 1;
border-color: rgba(129, 140, 248, var(--tw-border-opacity));
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);
box-shadow: var(--tw-ring-offset-shadow),
var(--tw-ring-shadow),
var(--tw-shadow, 0 0 #0000);
--tw-ring-opacity: 1;
--tw-ring-color: rgba(129, 140, 248, var(--tw-ring-opacity));
}
.is-invalid,
.was-validated :invalid,
.was-validated :invalid~label {
border-color: #dc3545;
}
.is-invalid,
.was-validated :invalid:focus {
--tw-ring-color: rgba(220, 53, 69, 0.2);
}
</style>
<script type="module" src="https://cdn.skypack.dev/twind/shim"></script>
<script src="https://cdn.jsdelivr.net/gh/alpinejs/[email protected]/dist/alpine.min.js" defer></script>
<div class="flex items-center justify-center min-h-screen py-6 bg-gray-50 sm:py-12">
<!-- // For demo purposes, I have open true by default and added open false on a time out
// For your project, its not needed. Just use x-data="{ open: false }" instead -->
<div class="relative" x-data=" data()" x-init="() => setTimeout(() => open = false, 2000)">
<button @click="open= !open; if (open) $nextTick(()=>{$refs.input.focus()});"
class="px-3 py-1 text-gray-500 bg-white rounded-md cursor-text ring-1 ring-gray-300 focus:outline-none ring-inset focus:ring-indigo-400 hover:ring-indigo-400">Feedback</button>
<div x-show="open" @click.away="open = false"
class="flex flex-col space-y-2 px-3 pt-1 pb-2 absolute z-10 w-[350px] min-h-[180px] bg-white top-0 left-0 rounded-md shadow-xl"
style=" --tw-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.04), 0 10px 10px -5px rgba(0, 0, 0, 0.03);">
<div class="text-gray-500">Feedback</div>
<div>
<!--
=======================================================================
This is a working feedback form. To receive email,
Replace "YOUR_ACCESS_KEY_HERE" with your actual Access Key below.
Create Access Key here 👉 https://web3forms.com/
=======================================================================
-->
<form action="https://api.web3forms.com/submit" method="POST" id="form" enctype="multipart/form-data"
@submit.prevent="submitForm($event.currentTarget)" class="needs-validation" novalidate>
<!-- Add your access key from Web3Forms here -->
<input type="hidden" name="apikey" value="YOUR_ACCESS_KEY_HERE" />
<input type="hidden" name="subject" value="New Feedback for your Website" />
<!-- {You might also want to pre-populate email if the user is logged in} -->
<!-- <input type="hidden" name="email" value="{user.email}" /> -->
<input type="checkbox" name="botcheck" id="" style="display: none;" />
<div class="mb-1">
<textarea x-ref="input" required name="message" id=""
class="w-full min-h-[100px] max-h-[300px] h-28 border-2 border-gray-200 rounded-md p-2 focus:outline-none focus:ring-4 focus:ring-indigo-50 focus:border-indigo-300"
placeholder="Let us know what you think..."></textarea>
</div>
<div class="flex items-center justify-between">
<div class="flex gap-2">
<div>
<input class="absolute opacity-0 appearance-none" required type="radio" id="happy" name="type"
value="happy" />
<label class="flex p-2 border border-gray-200 rounded-md cursor-pointer" for="happy">
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" width="20" height="20" viewBox="0 0 36 36">
<circle fill="#FFCC4D" cx="18" cy="18" r="18" />
<path fill="#664500"
d="M18 21c-3.623 0-6.027-.422-9-1-.679-.131-2 0-2 2 0 4 4.595 9 11 9 6.404 0 11-5 11-9 0-2-1.321-2.132-2-2-2.973.578-5.377 1-9 1z" />
<path fill="#FFF" d="M9 22s3 1 9 1 9-1 9-1-2 4-9 4-9-4-9-4z" />
<ellipse fill="#664500" cx="12" cy="13.5" rx="2.5" ry="3.5" />
<ellipse fill="#664500" cx="24" cy="13.5" rx="2.5" ry="3.5" />
</svg>
</label>
</div>
<div>
<input class="absolute opacity-0 appearance-none" required type="radio" id="sad" name="type"
value="sad" />
<label class="flex p-2 border border-gray-200 rounded-md cursor-pointer" for="sad">
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" width="20" height="20" viewBox="0 0 36 36">
<path fill="#FFCC4D"
d="M36 18c0 9.941-8.059 18-18 18-9.94 0-18-8.059-18-18C0 8.06 8.06 0 18 0c9.941 0 18 8.06 18 18" />
<ellipse fill="#664500" cx="11.5" cy="14.5" rx="2.5" ry="3.5" />
<ellipse fill="#664500" cx="24.5" cy="14.5" rx="2.5" ry="3.5" />
<path fill="#664500"
d="M8.665 27.871c.178.161.444.171.635.029.039-.029 3.922-2.9 8.7-2.9 4.766 0 8.662 2.871 8.7 2.9.191.142.457.13.635-.029.177-.16.217-.424.094-.628C27.3 27.029 24.212 22 18 22s-9.301 5.028-9.429 5.243c-.123.205-.084.468.094.628z" />
</svg>
</label>
</div>
<div>
<input class="absolute opacity-0 appearance-none" required type="radio" id="bug" name="type"
value="bug" />
<label class="flex p-2 border border-gray-200 rounded-md cursor-pointer" for="bug">
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" width="20" height="20" viewBox="0 0 36 36">
<path fill="#FFCC4D"
d="M2.653 35C.811 35-.001 33.662.847 32.027L16.456 1.972c.849-1.635 2.238-1.635 3.087 0l15.609 30.056c.85 1.634.037 2.972-1.805 2.972H2.653z" />
<path fill="#231F20"
d="M15.583 28.953c0-1.333 1.085-2.418 2.419-2.418 1.333 0 2.418 1.085 2.418 2.418 0 1.334-1.086 2.419-2.418 2.419-1.334 0-2.419-1.085-2.419-2.419zm.186-18.293c0-1.302.961-2.108 2.232-2.108 1.241 0 2.233.837 2.233 2.108v11.938c0 1.271-.992 2.108-2.233 2.108-1.271 0-2.232-.807-2.232-2.108V10.66z" />
</svg>
</label>
</div>
<div>
<input class="absolute opacity-0 appearance-none" required type="radio" id="idea" name="type"
value="idea" />
<label class="flex p-2 border border-gray-200 rounded-md cursor-pointer" for="idea">
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" width="20" height="20" viewBox="0 0 36 36">
<path fill="#FFD983"
d="M29 11.06c0 6.439-5 7.439-5 13.44 0 3.098-3.123 3.359-5.5 3.359-2.053 0-6.586-.779-6.586-3.361C11.914 18.5 7 17.5 7 11.06 7 5.029 12.285.14 18.083.14 23.883.14 29 5.029 29 11.06z" />
<path fill="#CCD6DD"
d="M22.167 32.5c0 .828-2.234 2.5-4.167 2.5-1.933 0-4.167-1.672-4.167-2.5 0-.828 2.233-.5 4.167-.5 1.933 0 4.167-.328 4.167.5z" />
<path fill="#FFCC4D"
d="M22.707 10.293c-.391-.391-1.023-.391-1.414 0L18 13.586l-3.293-3.293c-.391-.391-1.023-.391-1.414 0s-.391 1.023 0 1.414L17 15.414V26c0 .553.448 1 1 1s1-.447 1-1V15.414l3.707-3.707c.391-.391.391-1.023 0-1.414z" />
<path fill="#99AAB5" d="M24 31c0 1.104-.896 2-2 2h-8c-1.104 0-2-.896-2-2v-6h12v6z" />
<path fill="#CCD6DD"
d="M11.999 32c-.48 0-.904-.347-.985-.836-.091-.544.277-1.06.822-1.15l12-2c.544-.098 1.06.277 1.15.822.091.544-.277 1.06-.822 1.15l-12 2c-.055.01-.111.014-.165.014zm0-4c-.48 0-.904-.347-.985-.836-.091-.544.277-1.06.822-1.15l12-2c.544-.097 1.06.277 1.15.822.091.544-.277 1.06-.822 1.15l-12 2c-.055.01-.111.014-.165.014z" />
</svg>
</label>
</div>
</div>
<div class="flex items-center space-x-2">
<div id="thenga"> <label for="attachment"
:title="(files && files.length > 0) ? files.map(file => file.name).join(', ') : 'Choose a file...'"
class="relative flex items-center justify-center w-6 h-6 cursor-pointer">
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 text-gray-400" width="20" height="20"
fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M15.172 7l-6.586 6.586a2 2 0 102.828 2.828l6.414-6.586a4 4 0 00-5.656-5.656l-6.415 6.585a6 6 0 108.486 8.486L20.5 13" />
</svg>
<div id="badge"
class="absolute z-10 items-center justify-center w-4 h-4 text-xs font-bold text-white bg-red-500 rounded-full -right-1 -top-1"
:class="(files && files.length > 0) ? 'flex' : 'hidden'">
<span x-text="files?.length > 0 ? files.length : '0'">1</span></div>
<input type="file" id="attachment" name="attachment" accept="image/*"
x-on:change="files = Object.values($event.target.files); checkMaxSize($event.target.files) "
class="absolute w-px h-px overflow-hidden opacity-0 appearance-none ">
</label></div>
<button type="submit"
class="flex justify-center w-24 px-2 py-2 text-white bg-indigo-500 rounded-md focus:outline-none focus:ring focus:ring-indigo-300"
:disabled="submitting" id="submit">
<svg x-show="success" class="w-6 h-6">
<use href="#success" /></svg>
<svg x-show="error" class="w-6 h-6">
<use href="#error" /></svg>
<span x-show="!success && !error" x-text="submitting ? 'Sending...' : 'Send'">Send</span>
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<script>
function data() {
return {
open: true,
files: null,
submitting: false,
success: false,
error: false,
checkMaxSize(files) {
//console.table(files);
if (files.length > 0) {
{
for (const [key, value] of Object.entries(files)) {
const fileSize = value.size / 1024;
if (fileSize > 500) {
console.log(fileSize);
alert('Please upload image less than 500 KB');
this.files = null;
return;
}
}
}
};
},
async submitForm(form) {
console.log(form);
form.classList.add("was-validated");
if (!form.checkValidity()) {
console.log("Please fill all the fields");
form.querySelectorAll(":invalid")[0].focus();
} else {
const formData = new FormData(form);
this.submitting = true;
// needed for converting to JSON app/json
// const object = {};
// formData.forEach((value, key) => {
// object[key] = value;
// });
// const json = JSON.stringify(object);
// console.log(object);
try {
const response = await fetch("https://api.web3forms.com/submit", {
method: "POST",
body: formData
});
let json = await response.json();
this.submitting = false;
if (response.status == 200) {
this.success = true;
form.reset();
this.files = null;
} else {
this.error = true;
}
} catch (error) {
console.log(error);
}
form.classList.remove("was-validated");
setTimeout(() => {
this.open = false;
this.error = false;
this.success = false;
this.files = null;
}, 5000);
}
}
}
}
</script>
<div class="hidden">
<!-- Hidden SVG will show when it success -->
<svg id="success" xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 text-white" width="24" height="24" fill="none"
viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<svg id="error" xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 text-white" width="24" height="24" fill="none"
viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</div>
How to build a Quick Popover Feedback with Tailwind CSS?
Install tailwind css of verion 2.1.0
Use the script
html tag to import the script of Tailwind CSS of the version 2.1.0
<script src="https://cdn.tailwindcss.com"></script>
All the unility class needed to build a Quick Popover Feedback component
flex
min-h-screen
py-6
bg-gray-50
sm:py-12
relative
px-3
py-1
text-gray-500
bg-white
flex-col
pt-1
pb-2
absolute
z-10
w-[350px]
min-h-[180px]
top-0
left-0
mb-1
w-full
min-h-[100px]
max-h-[300px]
h-28
border-2
border-gray-200
p-2
focus:border-indigo-300
gap-2
w-5
h-5
w-6
h-6
text-gray-400
w-4
h-4
text-xs
text-white
bg-red-500
-right-1
-top-1
hidden
w-px
h-px
overflow-hidden
w-24
px-2
py-2
bg-indigo-500
49 steps to build a Quick Popover Feedback component with Tailwind CSS
Use
flex
to create a block-level flex container.Set the minimum width/height of an element using the
min-h-screen
utilities.Control the vertical padding of an element to 1.5rem using the
py-6
utilities.Control the background color of an element to gray-50 using the
bg-gray-50
utilities.Control the vertical padding of an element to 3rem at only small screen sizes using the
sm:py-12
utilities.Use
relative
to position an element according to the normal flow of the document.Control the horizontal padding of an element to 0.75rem using the
px-3
utilities.Control the vertical padding of an element to 0.25rem using the
py-1
utilities.Control the text color of an element to gray-500 using the
text-gray-500
utilities.Control the background color of an element to white using the
bg-white
utilities.Use
flex
to create a block-level flex container.Control the padding on top side of an element to 0.25rem using the
pt-1
utilities.Control the padding on bottom side of an element to 0.5rem using the
pb-2
utilities.Use
absolute
to position an element outside of the normal flow of the document, causing neighboring elements to act as if the element doesn’t exist.Control the stack order (or three-dimensional positioning) of an element to 10 in Tailwind, regardless of order it has been displayed, using the
z-10
utilities.Use
w-[350px]
to set an element to a fixed width([350px]).Set the minimum width/height of an element using the
min-h-[180px]
utilities.Use the
top-0
utilities to set the top position of a positioned element to 0rem.Use the
left-0
utilities to set the left position of a positioned element to 0rem.Control the margin on bottom side of an element to 0.25rem using the
mb-1
utilities.Use
w-full
to set an element to a 100% based width.Set the minimum width/height of an element using the
min-h-[100px]
utilities.Set the maximum width/height of an element using the
max-h-[300px]
utilities.Use
h-28
to set an element to a fixed height(7rem).Control the border color of an element to 0.5rem using the
border-2
utilities.Control the border color of an element to gray-200 using the
border-gray-200
utilities.Control the padding on all sides of an element to 0.5rem using the
p-2
utilities.Control the border color of an element to indigo-300 using the
focus:border-indigo-300
utilities on focus.To specify the width between columns, you can use the
gap-2
utilities.Use
w-5
to set an element to a fixed width(1.25rem).Use
h-5
to set an element to a fixed height(1.25rem).Use
w-6
to set an element to a fixed width(1.5rem).Use
h-6
to set an element to a fixed height(1.5rem).Control the text color of an element to gray-400 using the
text-gray-400
utilities.Use
w-4
to set an element to a fixed width(1rem).Use
h-4
to set an element to a fixed height(1rem).Control the text color of an element to xs using the
text-xs
utilities.Control the text color of an element to white using the
text-white
utilities.Control the background color of an element to red-500 using the
bg-red-500
utilities.Use the
-right-1
utilities to set the right position of a positioned element to -0.25rem.Use the
-top-1
utilities to set the top position of a positioned element to -0.25rem.Use
hidden
to set an element to display: none and remove it from the page layout.Use
w-px
to set an element to a fixed width(px).Use
h-px
to set an element to a fixed height(px).Use
overflow-hidden
to clip any content within an element that overflows the bounds of that element.Use
w-24
to set an element to a fixed width(6rem).Control the horizontal padding of an element to 0.5rem using the
px-2
utilities.Control the vertical padding of an element to 0.5rem using the
py-2
utilities.Control the background color of an element to indigo-500 using the
bg-indigo-500
utilities.
Conclusion
The above is a step-by-step tutorial on how to use Tailwind CSS to build a Quick Popover Feedback components, learn and follow along to implement your own components.