
Hello everyone, today we are going to create a circular menu with Tailwind CSS and JavaScript.
What is a Circular Menu?
A circular menu is a user interface element where menu items are arranged in a circular or radial layout, emanating from a central button or point. This type of menu is often used to save space and create a visually appealing, interactive navigation experience. When triggered, the menu items fan out in a circle or semi-circle around the central button, offering users quick access to various options.
Use Cases
Circular menus are particularly useful in the following scenarios:
- Mobile apps: Circular menus are often used in mobile applications to provide quick access to actions or tools without taking up too much screen space.
- Media or design apps: Circular menus allow users to select tools, colors, or actions in an intuitive, visually engaging way.
- Interactive dashboards: In dashboards or control panels, circular menus can be used to present grouped actions in a space-efficient manner.
- Gaming interfaces: Games often use circular menus to display options, tools, or weapons around a central point for quick selection.
- Navigation menus: For more creative or artistic websites, circular menus can be used to stand out and enhance the user experience.
Now, let’s write the markup
The wrapper
ID’s
id="menuContainer"
: This line of code will define the id of the wrapper. This id will be used to target the wrapper in the JavaScript code. Classesrelative
: This class will make the wrapper element relative to its position on the page.
<div
class="relative"
id="menuContainer">
<!-- Menu items goe here -->
</div>
The button
ID’s
id="menuToggle"
: This line of code will define the id of the button. This id will be used to target the button in the JavaScript code. Classesabsolute
: This class will make the button element absolutely positioned.top-1/2
: This class will position the button at the top of the screen, centered horizontally.left-1/2
: This class will position the button at the left of the screen, centered vertically.transform -translate-x-1/2 -translate-y-1/2
: This class will translate the button by half its width and half its height.
<button
id="menuToggle"
class="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2">
Menu
</button>
The links
The link wrapper
ID’s
id="circularMenu"
: This line of code will define the id of the link wrapper. Classesabsolute
: This class will make the link wrapper element absolutely positioned.top-0
: This class will make the link wrapper element start at the top of the page.left-0
: This class will make the link wrapper element start at the left of the page.w-full
: This class will make the link wrapper element take up the full width of the page.h-full
: This class will make the link wrapper element take up the full height of the page.- You can also use
size-full
instead ofw-full
andh-full
if you prefer.
The link items
Classes
menu-item
: This is a custom class that will be used to grab them with thequerySelectorAll
method.absolute
: This class will make the link items absolutely positioned.opacity-0
: This class will make the link items start with an opacity of 0.invisible
: This class will make the link items start with an opacity of 0 and also make them invisible.
<nav
id="circularMenu"
class="absolute top-0 left-0 w-full h-full">
<a href="#" class="absolute invisible opacity-0 menu-item ">1</a>
<a href="#" class="absolute invisible opacity-0 menu-item ">2</a>
<a href="#" class="absolute invisible opacity-0 menu-item ">3</a>
</nav>
The full markup
This is the full markup code for the circular menu with Tailwind CSS and JavaScript.Irrelevant classes have been omitted for brevity.
<div class="relative" id="menuContainer">
<button id="menuToggle" class="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2">
Menu
</button>
<nav id="circularMenu" class="absolute top-0 left-0 w-full h-full">
<a href="#" class="absolute invisible opacity-0 menu-item ">1</a>
<a href="#" class="absolute invisible opacity-0 menu-item ">2</a>
<a href="#" class="absolute invisible opacity-0 menu-item ">3</a>
</nav>
</div>
The JavaScript code
The variables
const menuToggle = document.getElementById("menuToggle");
: This line of code will get the button element with the id of “menuToggle” and store it in a variable calledmenuToggle
.const menuItems = document.querySelectorAll(".menu-item");
: This line of code will get all the link items with the class of “menu-item” and store them in a variable calledmenuItems
.let isOpen = false;
: This line of code will define a variable calledisOpen
and set its value tofalse
.
const menuToggle = document.getElementById("menuToggle");
const menuItems = document.querySelectorAll(".menu-item");
let isOpen = false;
The event listeners
menuToggle.addEventListener("click", toggleMenu);
: This line of code will add an event listener to the button element with the id of “menuToggle” that will call thetoggleMenu
function when the button is clicked.
menuToggle.addEventListener("click", toggleMenu);
The toggleMenu function
The toggleMenu
function will be used to toggle the visibility of the menu items.
function toggleMenu() {
: This line of code will define a function calledtoggleMenu
that will be called when the button is clicked.isOpen = !isOpen;
: This line of code will toggle the value ofisOpen
fromfalse
totrue
and vice versa.menuItems.forEach((item, index) => {
: This line of code will iterate over each link item in themenuItems
array and pass the link item and its index to the anonymous function.const delay = index * 50;
: This line of code will define a variable calleddelay
and set its value toindex * 50
.setTimeout(() => {
: This line of code will use thesetTimeout
function to delay the execution of the following code bydelay
milliseconds.if (isOpen) {
: This line of code will check ifisOpen
istrue
.const angle = (index / menuItems.length) * 2 * Math.PI;
: This line of code will define a variable calledangle
and set its value to(index / menuItems.length) * 2 * Math.PI
.const radius = 50;
: This line of code will define a variable calledradius
and set its value to50
.const x = Math.cos(angle) * radius + 50;
: This line of code will define a variable calledx
and set its value toMath.cos(angle) * radius + 50
.const y = Math.sin(angle) * radius + 50;
: This line of code will define a variable calledy
and set its value toMath.sin(angle) * radius + 50
.item.style.left =
${x}%;
: This line of code will set theleft
style of the link item tox
percent.item.style.top =
${y}%;
: This line of code will set thetop
style of the link item toy
percent.item.classList.remove("opacity-0", "invisible");
: This line of code will remove theopacity-0
andinvisible
classes from the link item.item.style.transform =
translate(-50%, -50%) scale(1);
: This line of code will set thetransform
style of the link item totranslate(-50%, -50%) scale(1)
.} else {
: This line of code will close the menu ifisOpen
isfalse
.item.style.left = "50%";
: This line of code will set theleft
style of the link item to50%
.item.style.top = "50%";
: This line of code will set thetop
style of the link item to50%
.item.classList.add("opacity-0", "invisible");
: This line of code will add theopacity-0
andinvisible
classes to the link item.item.style.transform =
translate(-50%, -50%) scale(0.5);
: This line of code will set thetransform
style of the link item totranslate(-50%, -50%) scale(0.5)
.}, delay);
: This line of code will close the menu ifisOpen
isfalse
.menuToggle.textContent = isOpen ? "Close" : "Menu";
: This line of code will toggle the text of the button ifisOpen
istrue
orfalse
.
function toggleMenu() {
isOpen = !isOpen;
menuItems.forEach((item, index) => {
const delay = index * 50; // Stagger the animation
setTimeout(() => {
if (isOpen) {
const angle = (index / menuItems.length) * 2 * Math.PI;
const radius = 50; // Reduced radius to bring items closer to the button
const x = Math.cos(angle) * radius + 50;
const y = Math.sin(angle) * radius + 50;
item.style.left = `${x}%`;
item.style.top = `${y}%`;
item.classList.remove("opacity-0", "invisible");
item.style.transform = `translate(-50%, -50%) scale(1)`;
} else {
item.style.left = "50%";
item.style.top = "50%";
item.classList.add("opacity-0", "invisible");
item.style.transform = `translate(-50%, -50%) scale(0.5)`;
}
}, delay);
});
// Toggle the menu button text
menuToggle.textContent = isOpen ? "Close" : "Menu";
}
const menuToggle = document.getElementById("menuToggle");
const menuItems = document.querySelectorAll(".menu-item");
let isOpen = false;
menuToggle.addEventListener("click", toggleMenu);
function toggleMenu() {
isOpen = !isOpen;
menuItems.forEach((item, index) => {
const delay = index * 50; // Stagger the animation
setTimeout(() => {
if (isOpen) {
const angle = (index / menuItems.length) * 2 * Math.PI;
const radius = 50; // Reduced radius to bring items closer to the button
const x = Math.cos(angle) * radius + 50;
const y = Math.sin(angle) * radius + 50;
item.style.left = `${x}%`;
item.style.top = `${y}%`;
item.classList.remove("opacity-0", "invisible");
item.style.transform = `translate(-50%, -50%) scale(1)`;
} else {
item.style.left = "50%";
item.style.top = "50%";
item.classList.add("opacity-0", "invisible");
item.style.transform = `translate(-50%, -50%) scale(0.5)`;
}
}, delay);
});
// Toggle the menu button text
menuToggle.textContent = isOpen ? "Close" : "Menu";
}
Conclusion
This is a simple circular menu that you can recreate with Tailwind CSS and JavaScript. You can customize the colors, number of menu items, and radius to your liking.
Hope you enjoyed this tutorial and have a good day!
/Michael Andreuzza
Unlock all themes for $149 and own them forever! Includes lifetime updates, new themes, unlimited projects, and support
