Glassmorphism✨ Premium

Neu Calculator

A 260 × 372 px neumorphic calculator that really calculates: inset display, 19 raised keys that press in on click, a purple-gradient = key; chained operations, %, ±, division by zero shown as “Err”, results rounded to 12 digits — and several independent calculators on the same page.

CSSJSInteractive

Updated

This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Glassmorphism has 47 effects, including 6 free. Explore the category →

3 usage examples

Converting currencies — a bureau de change kiosk — Neu Calculator example 1

① Converting currencies — a bureau de change kiosk

WhenThe traveller has a €350 budget and wants to know how many pounds they will get: they type 350 × 0.8412 = on the kiosk, next to the board of today's rates.
WhyIt is a real working keypad, with keys that press in like a counter calculator; the inset display keeps the result readable (294.42). Relief without loud color suits counter furniture, and purple only marks the action: operators and =.
SettingsCalculator 250 px wide, 38 px keys and an 8 px gap to fit the kiosk screen (padding: 16px, 48 px display); surface and scene background in #e0e5ec, the case's tint. Rate board carved with the same inset shadow as the display. Input played automatically for the capture.
Price by weight — touch scale in a bulk grocery — Neu Calculator example 2

② Price by weight — touch scale in a bulk grocery

WhenThe cashier adds two weighings (lentils €2.84, almonds €6.00) then applies the 10% “bring your jar” discount: 2.84 + 6 × 90 % =.
WhyLeft-to-right chaining and the % key cover the till calculation with no special mode: the + is resolved as soon as × is pressed, then 90 % becomes 0.9, and the display shows 7.956 — rounded to the cent on the ticket. The relief imitates the scale's rubber keypad.
SettingsCalculator at 230 px, 36 px keys, 44 px display; the ticket on the right is a raised card (6px 6px 12px) on the same #e0e5ec surface. The discount is typed × 90 %: with this code, − 10 % would subtract 0.1, not 10%.
Measurements and cutting list — a joiner's workshop tablet — Neu Calculator example 3

③ Measurements and cutting list — a joiner's workshop tablet

WhenBefore cutting, the joiner adds up the lengths: three 842 mm shelves and two 1,200 mm uprights, 842 × 3 + 2400 = 4926, to compare with the two 2,500 mm rough boards.
WhyBig raised keys are easy to hit with dusty hands, and the carved display stays readable under workshop light. No color to interpret: shape alone tells what can be pressed.
SettingsKeys at their original height (44 px) and the case widened to 300 px with 16 px padding: each key is 61 px wide. 8 px gap, original display (56 px, 24 px number). Parts list as small raised cards, same #e0e5ec surface.

How it works

All the relief comes from two shadows on a single tint. The case .neu-calc (260 × 372 px, padding: 20px, border-radius: 24px) is painted #e0e5ec and carries #b8bec7 10px 10px 20px bottom right and #fff -10px -10px 20px top left: the light comes from the top-left corner. The display .neu-calc-display (220 × 56 px, 14 px radius) takes the same shadows as inset at 4 px — it is carved into the case — and right-aligns the number in 24 px bold, #374151. The grid .neu-calc-grid lays out 19 <button>s in 4 columns (47.5 × 44 px, 10 px gap, 12 px radius), the 0 spans two columns. Each key is raised (4px 4px 8px) and turns hollow on :active (inset 2px 2px 4px), with transition: .15s: measured in Chromium, Firefox and WebKit, the computed shadow under the finger is indeed the inverted one. Operators are purple #8b5cf6, the = key a 135deg gradient #8b5cf6 → #a78bfa with a 12 px purple glow.

The JavaScript (an IIFE, nothing global) creates one instance per .neu-calc found in the page and listens to clicks on the case; each key carries its value in data-key. Operations chain from left to right, like a pocket or till calculator: 12 + 30 × 2 = gives 84 (not 72, there is no operator precedence). % divides the displayed value by 100: 200 % → 2, so 12.5 × 80 % = 10; but 12.5 − 20 % = 12.3 (the key does not compute “20% of 12.5”). ± flips the sign, C resets everything, a second decimal point is ignored. 5 ÷ 0 = shows Err; after that only a digit or C is accepted. Results are rounded to 12 significant digits (0.1 + 0.2 shows 0.3) and switch to 1.42857143e-3 notation beyond 15 characters; input stops at 14 digits, which the display holds without overflowing even with a minus sign (measured in all three engines: 9 px to spare for − and 14 digits; 16 digits would overflow by 10 px). The decimal separator is the point.

Four decisions, each checked by a measurement. The background: set on a black frame, the calculator's light #fff shadow would become a halo (19.8:1 against black, 1.3:1 on its own surface); the .demo-preview frame therefore declares the same #e0e5ec surface and 32 px of vertical margin, without imposing anything on body. One instance per calculator: no global function called through onclick, no display looked up by id — with those two shortcuts, two copies on a page get mixed up (4 and 2 typed on the second write “42” into the first); the script also works under a security policy that forbids inline scripts. Decimals: results are rounded, otherwise 0.1 + 0.2 would show 0.30000000000000004, and input is capped so the 16th digit never leaves the display. After a division by zero, only fresh input is accepted, so NaN never shows. The keys carry type="button": placed inside a form, they do not submit it (checked).

Accessibility

  • Keyboard: the 19 keys are real <button>s. Measured in all three engines, Tab walks through them in reading order (C first), Enter and Space activate them (7 twice → “77”), and the browser focus ring stays visible (outline: auto). Physical keyboard keys (digits, +, Enter) are not listened to: for a kiosk or a touch scale it does not matter; on a website, add a keydown handler that triggers the same click on [data-key].
  • Screen readers: the display is a plain div; its changes are not announced. Add role="status" (or aria-live="polite") on .neu-calc-display so the result is read after =. The ±, ×, ÷ and − keys are read by their symbol, differently depending on the reader: an aria-label (“plus or minus”, “multiply”, “divide”, “minus”) removes the ambiguity.
  • Contrast: the display number #374151 on #e0e5ec measures 8.1:1. Key digits #6b7280 (14.4 px, weight 600) only measure 3.8:1 and operators #8b5cf6 3.3:1, below the 4.5:1 threshold for body text; the white of the = key drops to 2.7:1 on the light end of the #a78bfa gradient (4.2:1 on #8b5cf6). Darken digits to #4b5563 (6.0:1) and operators to #6d28d9 (5.6:1) if the calculator is used for purchases. The relief itself is low-contrast by nature (dark shadow 1.5:1, light shadow 1.3:1 on the surface): key shape must not be the only cue — here the symbol is.
  • Motion: only the shadow changes, in 0.15 s, and only while pressing. No movement, no continuous animation: prefers-reduced-motion has nothing to cut.

Browser compatibility

CSS: double and inset box-shadow, CSS grid, linear-gradient, :active. JavaScript: querySelectorAll().forEach, closest(), toPrecision() — no library, no external resource. Tested pasted into a blank page in Chromium 151, Firefox 153 and Playwright's WebKit 26.5: same results for the same calculations (84, 2, Err, 0.3, 1.42857143e-3), same shadow on :active, two independent calculators. The requested font is Inter: if it is not loaded on your page, the browser uses its default sans-serif font and digit widths vary slightly (14 digits and the sign fit in the display with the default font of Chromium, Firefox and WebKit, measured).

Chrome 51+✓ Full
Firefox 50+✓ Full
Safari 10+✓ Full
Edge 79+✓ Full
Mobile iOS✓ Full (press-in visible on touch: see below)
Android Chrome✓ Full

Without JavaScript, the calculator displays in full (display at 0, raised keys that press in) but does not calculate. NodeList.forEach is missing before Chrome 51, Firefox 50 and Safari 10: replace it with Array.prototype.forEach.call if you target those versions. On iOS, Safari only applies :active on touch if a touchstart listener exists on the page (behavior documented by Apple, not measured here): document.addEventListener('touchstart', function () {}, { passive: true }) is enough to see keys press in under the finger; the calculation itself works either way.

The code

HTML structure to paste into your page (the CSS + JS come with Premium):

index.html — structure
<div class="demo-preview">
  <div class="neu-calc-scene">
    <div class="neu-calc">
      <div class="neu-calc-display">0</div>
      <div class="neu-calc-grid">
        <button type="button" class="neu-calc-key neu-calc-key--op" data-key="C">C</button>
        …
        <button type="button" class="neu-calc-key" data-key="7">7</button>
        …
        <button type="button" class="neu-calc-key neu-calc-key--eq" data-key="=">=</button>
      </div>
    </div>
  </div>
</div>
Unlock the full code — $9.90/mo incl. tax

The full HTML + CSS + JS of Neu Calculator, ready to paste — plus all 840 effects. Or $299 once, lifetime access.

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Surface tint (CSS — background: #e0e5ec on .neu-calc, the display, the keys and .demo-preview) #e0e5ec (bluish gray) Change it everywhere at once: neumorphism only works when background and surface share the same tint. Then recompute both shadows: one about 15% darker (#b8bec7 here) and one lighter (#fff). On a background of another tint, the light shadow turns into a halo.
Relief depth (CSS — box-shadow of .neu-calc and .neu-calc-key) case 10 px / 20 px blur · keys 4 px / 8 px Keep the blur at twice the offset. Beyond 6 px on keys, the shadows of two neighboring keys overlap in the 10 px gap.
Key size (CSS — .neu-calc-key { height: 44px }, .neu-calc-grid { gap: 10px }, .neu-calc { width: 260px }) 47.5 × 44 px, 10 px gap Width follows the case (4 columns). 300 px wide gives 57.5 px keys (61 px with 16 px padding and an 8 px gap, as in the workshop scene). 38 px high with an 8 px gap brings the case from 372 down to 334 px.
Operator and = color (CSS — .neu-calc-key--op { color }, .neu-calc-key--eq { background }) #8b5cf6 and #8b5cf6 → #a78bfa gradient One accent color is enough. For readability, aim for 4.5:1 on #e0e5ec: #6d28d9 gives 5.6:1, the original purple 3.3:1.
Add or rename a key (HTML — data-key) C, ±, %, ÷, ×, -, +, =, ., 0-9 The button text is free (“AC”, “−”); only the data-key value matters to the calculation. Minus is written data-key="-", even when the key shows “−”.
Input length (JS — cur.replace("-", "").length >= 14; results: cur.length > 15) 14 digits typed, 15 characters displayed Adjust both to the display width: about 13.4 px per digit at 24 px. With a narrower display (the scale scene, 202 px) or a wider font, lower both limits together.

FAQ

Because the calculator chains from left to right, like a pocket or till calculator: when × is pressed, the pending 12 + 30 is computed (42), then × 2 gives 84. Scientific calculators apply operator precedence (72). For giving change, a weighing or a sum of measurements, chaining is what the user expects; for formulas you would need an expression parser, which this code does not have.
Type 12.5 × 80 % =: the % key divides the displayed value by 100, so 80 % becomes 0.8 and the result is 10 (measured). 12.5 − 20 % = gives 12.3, because 20 % is 0.2, not “20% of 12.5”. Some phone calculators treat % differently after + or −; this one keeps a single rule, easy to explain next to a till.
Yes. The script creates one instance per .neu-calc element present at load: each has its own display and calculations (measured with two copies — 42 typed on the second, the first stays at 0). There is no id and no global function. For a calculator added after load (a modal), run the initialization block again on that new element.