Copy URL or Code
Paste to your AI coding assistant and customize:
Done. Your AI handles the rest.
Fully customizable. Shows up, down, nested, and button states for both square and circle shapes. Supports light/dark themes.
"use client";
/*
================================================================================
NEUMORPHISM KEYBOARD BUTTON - React Component
================================================================================
WHAT THIS DOES:
- Soft UI buttons with raised/inset shadow effects (neumorphism style)
- 4 button types: nested (raised+pressed), interactive, sphere-up, sphere-down
- 3 themes: light (gray), dark, maroon accent
HOW TO CUSTOMIZE:
┌─────────────────┬────────────────────────────────────────────────────────────┐
│ Change size │ Edit --key-size in CSS (default: 5rem) │
│ Change colors │ Edit --accent, --accent-highlight, --accent-shade │
│ Change labels │ Edit text inside <div className="neu-key"> │
│ Add buttons │ Copy neu-key HTML, use classes: raised, pressed, interactive│
│ Make circular │ Add neu-key--circular class │
│ Change spacing │ Edit --gap in CSS │
│ Change font │ Edit font-family in .keyboard-container │
└─────────────────┴────────────────────────────────────────────────────────────┘
BUTTON CLASSES REFERENCE:
- "neu-key raised" → Raised button (shadow outside)
- "neu-key pressed" → Pressed button (shadow inside)
- "neu-key interactive" → Interactive (press effect on hover)
- "neu-key neu-key--circular"→ Circular shape
- "neu-key sphere-up" → Circle with raised effect
- "neu-key sphere-down" → Circle with pressed effect
- "accent-outer/inner" → Colored accent (use with isMaroon condition)
================================================================================
*/
import React from "react";
interface NeumorphismPrinciplesProps {
theme?: "light" | "dark" | "maroon";
className?: string;
}
export function NeumorphismPrinciples({
theme = "light",
className = "",
}: NeumorphismPrinciplesProps) {
const isDark = theme === "dark";
const isMaroon = theme === "maroon";
return (
<div className={`keyboard-container ${className}`}>
{/* Row 1: Square keys */}
<div className={`neu-key nested raised ${isMaroon ? "accent-outer" : ""}`}>
<div className={`neu-key pressed ${isMaroon ? "accent-inner" : ""}`}>
Up &<br />Down
</div>
</div>
<div className="neu-key interactive">
<div className="neu-key">
<span>Button</span>
</div>
</div>
{/* Row 2: Circular keys */}
<div className="neu-key neu-key--circular sphere-up">Up</div>
<div className="neu-key neu-key--circular sphere-down">Down</div>
<style jsx>{`
@import url("https://fonts.googleapis.com/css2?family=Alumni+Sans+Pinstripe&display=swap");
.keyboard-container {
--key-size: 5rem;
--radius: 1rem;
--gap: 1rem;
--offset-lg: 5px;
--offset-sm: 4px;
--blur: 10px;
--bg: ${isDark ? "#333" : "#ddd"};
--highlight: ${isDark ? "rgba(255, 255, 255, 0.15)" : "rgba(255, 255, 255, 0.5)"};
--shade: ${isDark ? "rgba(0, 0, 0, 0.7)" : "rgba(0, 0, 0, 0.5)"};
--text-color: ${isDark ? "#eee" : "#333"};
--accent: #800020;
--accent-highlight: rgba(180, 60, 80, 0.3);
--accent-shade: rgba(80, 0, 20, 0.5);
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
align-content: center;
gap: var(--gap);
width: 100%;
height: 100%;
padding: 1.5rem;
background-color: var(--bg);
font-size: 1.5rem;
color: var(--text-color);
line-height: 0.9;
font-family: "Alumni Sans Pinstripe", sans-serif;
text-transform: uppercase;
text-align: center;
}
.neu-key {
position: relative;
display: flex;
justify-content: center;
align-items: center;
width: var(--key-size);
height: var(--key-size);
border-radius: var(--radius);
}
.neu-key::before, .neu-key::after {
content: "";
position: absolute;
top: 0; left: 0;
width: 100%; height: 100%;
border-radius: var(--radius);
}
.neu-key--circular { border-radius: 50%; }
.neu-key--circular::before { border-radius: 50%; }
.nested { padding: 0.125rem; }
.accent-outer {
background-color: var(--accent);
box-shadow: var(--accent-shade) var(--offset-lg) var(--offset-lg) var(--blur);
}
.accent-outer::before {
box-shadow: var(--accent-highlight) calc(-1 * var(--offset-lg)) calc(-1 * var(--offset-lg)) var(--blur);
}
.accent-inner {
background-color: var(--accent);
color: #fff;
box-shadow: inset var(--accent-shade) var(--offset-sm) var(--offset-sm) var(--blur);
}
.accent-inner::before {
box-shadow: inset var(--accent-highlight) calc(-1 * var(--offset-sm)) calc(-1 * var(--offset-sm)) var(--blur);
}
.raised { box-shadow: var(--shade) var(--offset-lg) var(--offset-lg) var(--blur); }
.raised::before { box-shadow: var(--highlight) calc(-1 * var(--offset-lg)) calc(-1 * var(--offset-lg)) var(--blur); }
.pressed { box-shadow: inset var(--shade) var(--offset-sm) var(--offset-sm) var(--blur); }
.pressed::before { box-shadow: inset var(--highlight) calc(-1 * var(--offset-sm)) calc(-1 * var(--offset-sm)) var(--blur); }
.interactive {
cursor: pointer;
box-shadow: var(--shade) var(--offset-lg) var(--offset-lg) var(--blur);
transition: box-shadow 180ms ease;
}
.interactive::before {
box-shadow: var(--highlight) calc(-1 * var(--offset-lg)) calc(-1 * var(--offset-lg)) var(--blur);
transition: box-shadow 180ms ease;
}
.interactive span { transition: transform 200ms ease-out; }
.interactive > .neu-key {
box-shadow: inset var(--shade) 0 0 0;
transition: box-shadow 180ms ease;
}
.interactive > .neu-key::before {
box-shadow: inset var(--highlight) 0 0 0;
transition: box-shadow 180ms ease;
}
.interactive:hover { box-shadow: var(--shade) 0 0 0; }
.interactive:hover::before { box-shadow: var(--highlight) 0 0 0; }
.interactive:hover > .neu-key {
box-shadow: inset var(--shade) var(--offset-sm) var(--offset-sm) var(--blur);
transition: box-shadow 180ms 100ms ease;
}
.interactive:hover > .neu-key::before {
box-shadow: inset var(--highlight) calc(-1 * var(--offset-sm)) calc(-1 * var(--offset-sm)) var(--blur);
transition: box-shadow 180ms 100ms ease;
}
.interactive:hover span { transform: translateY(2px); }
.sphere-up {
background: radial-gradient(circle at 38% 38%, var(--highlight), transparent, var(--shade));
box-shadow: var(--shade) var(--offset-lg) var(--offset-lg) var(--blur);
}
.sphere-down {
background: radial-gradient(circle at 72% 72%, var(--highlight), transparent, var(--shade));
}
`}</style>
</div>
);
}
export default NeumorphismPrinciples;// === BASIC USAGE ===
import NeumorphismPrinciples from "@/components/NeumorphismPrinciples";
// Light theme (default)
<NeumorphismPrinciples />
// Dark theme
<NeumorphismPrinciples theme="dark" />
// Maroon accent theme
<NeumorphismPrinciples theme="maroon" />
// === CUSTOMIZATION EXAMPLES ===
// 1. Change size - modify --key-size variable
// 2. Custom accent color - override CSS variables:
.my-custom-keyboard {
--accent: #2563eb;
--accent-highlight: rgba(37, 99, 235, 0.3);
--accent-shade: rgba(30, 58, 138, 0.5);
}
// 3. Add more buttons - copy neu-key structure:
<div className="neu-key raised">New</div>
<div className="neu-key pressed">Pressed</div>
<div className="neu-key interactive">
<div className="neu-key"><span>Click</span></div>
</div>