Circle of Fifths
I want to create a clickable Circle of Fifths, with proper border and background colour like the image above, but have not been able to successfully create one in HTML/CSS. I’m looking for alternative solutions/mistakes in my approach.
My approach is the following:
CircleOfFifths.css
.key-pair:nth-child(1) .major-container {
transform: rotate(0deg) translate(120px) rotate(0deg);
}
.key-pair:nth-child(1) .minor-container {
transform: rotate(0deg) translate(90px) rotate(0deg) translateY(-20px);
}
.key-pair:nth-child(2) .major-container {
transform: rotate(30deg) translate(120px) rotate(-30deg);
}
.key-pair:nth-child(2) .minor-container {
transform: rotate(30deg) translate(90px) rotate(-30deg) translateY(-20px);
}
.key-pair:nth-child(3) .major-container {
transform: rotate(60deg) translate(120px) rotate(-60deg);
}
.key-pair:nth-child(3) .minor-container {
transform: rotate(60deg) translate(90px) rotate(-60deg) translateY(-20px);
}
.key-pair:nth-child(4) .major-container {
transform: rotate(90deg) translate(120px) rotate(-90deg);
}
.key-pair:nth-child(4) .minor-container {
transform: rotate(90deg) translate(90px) rotate(-90deg) translateY(-20px);
}
.key-pair:nth-child(5) .major-container {
transform: rotate(120deg) translate(120px) rotate(-120deg);
}
.key-pair:nth-child(5) .minor-container {
transform: rotate(120deg) translate(90px) rotate(-120deg) translateY(-20px);
}
.key-pair:nth-child(6) .major-container {
transform: rotate(150deg) translate(120px) rotate(-150deg);
}
.key-pair:nth-child(6) .minor-container {
transform: rotate(150deg) translate(90px) rotate(-150deg) translateY(-20px);
}
.key-pair:nth-child(7) .major-container {
transform: rotate(180deg) translate(120px) rotate(-180deg);
}
.key-pair:nth-child(7) .minor-container {
transform: rotate(180deg) translate(90px) rotate(-180deg) translateY(-20px);
}
.key-pair:nth-child(8) .major-container {
transform: rotate(210deg) translate(120px) rotate(-210deg);
}
.key-pair:nth-child(8) .minor-container {
transform: rotate(210deg) translate(90px) rotate(-210deg) translateY(-20px);
}
.key-pair:nth-child(9) .major-container {
transform: rotate(240deg) translate(120px) rotate(-240deg);
}
.key-pair:nth-child(9) .minor-container {
transform: rotate(240deg) translate(90px) rotate(-240deg) translateY(-20px);
}
.key-pair:nth-child(10) .major-container {
transform: rotate(270deg) translate(120px) rotate(-270deg);
}
.key-pair:nth-child(10) .minor-container {
transform: rotate(270deg) translate(90px) rotate(-270deg) translateY(-20px);
}
.key-pair:nth-child(11) .major-container {
transform: rotate(300deg) translate(120px) rotate(-300deg);
}
.key-pair:nth-child(11) .minor-container {
transform: rotate(300deg) translate(90px) rotate(-300deg) translateY(-20px);
}
.key-pair:nth-child(12) .major-container {
transform: rotate(330deg) translate(120px) rotate(-330deg);
}
.key-pair:nth-child(12) .minor-container {
transform: rotate(330deg) translate(90px) rotate(-330deg) translateY(-20px);
}
CircleOfFifths.tsx – the actual component
import React, { useState } from "react";
import "./CircleOfFifths.css"; // Import CSS file for custom styles
const keys = [
{ major: "C", minor: "Am" },
{ major: "G", minor: "Em" },
{ major: "D", minor: "Bm" },
{ major: "A", minor: "F#m" },
{ major: "E", minor: "C#m" },
{ major: "B", minor: "G#m" },
{ major: "F#", minor: "D#m" },
{ major: "Db", minor: "Bbm" },
{ major: "Ab", minor: "Fm" },
{ major: "Eb", minor: "Cm" },
{ major: "Bb", minor: "Gm" },
{ major: "F", minor: "Dm" },
];
const CircleOfFifths = () => {
const [selectedKey, setSelectedKey] = useState("C");
const [expanded, setExpanded] = useState(false);
return (
<div className="relative">
<div
className={`circle ${expanded ? "expanded" : ""}`}
onClick={() => setExpanded(!expanded)}
style={{
backgroundColor: "#141429",
color: "#758599",
border: "1px solid rgba(0, 0, 0, 0.12)",
}}
>
{!expanded && <span className="selected-key">{selectedKey}</span>}
{expanded && (
<div className="circle-content">
{keys.map((key, index) => (
<div key={index} className="key-pair">
<div
className="key-container major-container"
onClick={() => {
setSelectedKey(key.major);
setExpanded(false);
}}
>
<div className="key">{key.major}</div>
</div>
<div
className="key-container minor-container"
onClick={() => {
setSelectedKey(key.minor);
setExpanded(false);
}}
>
<div className="key">{key.minor}</div>
</div>
</div>
))}
</div>
)}
</div>
</div>
);
};
export default CircleOfFifths;
This method correctly places the letters in a circle, but I cannot place a border correctly, and i suspect there is a better approach. Thanks for the help in advance.
Raifa is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.