WEBLEB
Home
Editor
Login
Pro
English
English
Français
Español
Português
Deutsch
Italiano
हिंदी
Recording Toggle
1493
Andev.web
Open In Editor
Publish Your Code
Recommended
13 April 2024
HTML CSS Toggle Button
30 March 2025
+- Toggle
14 September 2024
Minion Eye Toggle
HTML
Copy
Andev Web
CSS
Copy
* { border: 0; box-sizing: border-box; margin: 0; padding: 0; } :root { --hue: 223; --red: hsl(3,90%,50%); --white: hsl(0,0%,100%); --primary: hsl(var(--hue),90%,50%); --primary-t: hsla(var(--hue),90%,50%,0); --gray1: hsl(var(--hue),10%,90%); --gray2: hsl(var(--hue),10%,80%); --gray3: hsl(var(--hue),10%,70%); --gray4: hsl(var(--hue),10%,60%); --gray5: hsl(var(--hue),10%,50%); --gray6: hsl(var(--hue),10%,40%); --gray7: hsl(var(--hue),10%,30%); --gray8: hsl(var(--hue),10%,20%); --gray9: hsl(var(--hue),10%,10%); --trans-dur: 0.3s; --trans-timing: cubic-bezier(0.65,0,0.35,1); font-size: calc(28px + (60 - 28) * (100vw - 320px) / (3840 - 320)); } body, button { color: var(--gray9); font: 1em/1.5 "DM Sans", sans-serif; transition: background-color var(--trans-dur), color var(--trans-dur); } body { background-color: var(--gray1); } .recorder { background-color: transparent; cursor: pointer; display: flex; align-items: center; margin: auto; outline: transparent; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); -webkit-appearance: none; appearance: none; -webkit-tap-highlight-color: transparent; } .recorder__label-start, .recorder__label-end { display: block; position: relative; } .recorder__label-start, .recorder__label-end-text { transition: opacity var(--trans-dur); } .recorder__label-start { margin-inline: 0 0.5em; } .recorder__label-end { margin-inline: 0.5em 0; } .recorder__label-end-text { opacity: 0.4; } .recorder__label-end-text + .recorder__label-end-text { opacity: 0; position: absolute; top: 0; left: 0; } [dir=rtl] .recorder__label-end-text + .recorder__label-end-text { right: 0; left: auto; } .recorder__switch { background-color: var(--white); border-radius: 0.75em; box-shadow: 0 0 0 0.125em var(--primary-t), 0 0.25em 0.25em rgba(0, 0, 0, 0.1); display: flex; padding: 0.25em; width: 2.5em; height: 1.5em; } .recorder__switch, .recorder__switch-handle { transition: background-color var(--trans-dur), box-shadow var(--trans-dur), transform var(--trans-dur) var(--trans-timing), transform-origin var(--trans-dur) var(--trans-timing); } .recorder__switch-handle { background-color: var(--gray3); border-radius: 50%; display: block; transform-origin: 0 0.5em; width: 1em; height: 1em; } [dir=rtl] .recorder__switch-handle { transform-origin: 100% 0.5em; } .recorder__timer { display: block; overflow: visible; width: 100%; height: auto; } .recorder__timer-ring { transition: r var(--trans-dur) var(--trans-timing), stroke-dasharray var(--trans-dur) var(--trans-timing), stroke-dashoffset var(--trans-dur) var(--trans-timing), stroke-width var(--trans-dur) var(--trans-timing); } .recorder:focus-visible .recorder__switch { box-shadow: 0 0 0 0.125em var(--primary), 0 0.25em 0.25em rgba(0, 0, 0, 0.1); } .recorder:active .recorder__switch-handle { transform: scaleX(1.5); } .recorder[aria-pressed=true] .recorder__label-start { opacity: 0.4; } .recorder[aria-pressed=true] .recorder__label-end-text { opacity: 0; } .recorder[aria-pressed=true] .recorder__label-end-text + .recorder__label-end-text { opacity: 1; } .recorder[aria-pressed=true] .recorder__switch-handle { background-color: var(--red); transform: translateX(100%); transform-origin: 100% 0.5em; } [dir=rtl] .recorder[aria-pressed=true] .recorder__switch-handle { transform: translateX(-100%); transform-origin: 0 0.5em; } .recorder[aria-pressed=true] .recorder__timer-ring { r: 6.5px; stroke-width: 3px; } .recorder[aria-pressed=true]:active .recorder__switch-handle { transform: translateX(100%) scaleX(1.5); } [dir=rtl] .recorder[aria-pressed=true]:active .recorder__switch-handle { transform: translateX(-100%) scaleX(1.5); } /* Dark theme */ @media (prefers-color-scheme: dark) { body, button { color: var(--gray1); } body { background-color: var(--gray9); } .recorder__switch { background-color: var(--gray8); box-shadow: 0 0 0 0.125em var(--primary-t), 0 0.25em 0.25em rgba(0, 0, 0, 0.2); } .recorder__switch-handle { background-color: var(--gray6); } .recorder:focus-visible .recorder__switch { box-shadow: 0 0 0 0.125em var(--primary), 0 0.25em 0.25em rgba(0, 0, 0, 0.2); } }
JS
Copy
import React, { StrictMode, useEffect, useState } from "https://esm.sh/react"; import { createRoot } from "https://esm.sh/react-dom/client"; createRoot(document.getElementById("root")).render(React.createElement(StrictMode, null, React.createElement(RecordingToggle, null))); function RecordingToggle() { const [recording, setRecording] = useState(false); const [time, setTime] = useState(0); const timeMax = 60; const [timeStopped, setTimeStopped] = useState(0); const circumference = recording ? 40.84 : 50.27; const circumferencePart = recording ? 1 - (time / timeMax) : 1; const strokeDashArray = `${circumference} ${circumference}`; const strokeDashOffset = +(circumference * circumferencePart).toFixed(2); function timeFormatted() { const timeToDisplay = recording ? time : timeStopped; const minutes = `0${Math.floor(timeToDisplay / 60)}`.slice(-2); const seconds = `0${timeToDisplay % 60}`.slice(-2); return `${minutes}:${seconds}`; } // timer loop useEffect(() => { let frameId = 0; if (recording) { setTimeStopped(0); const render = () => { setTime((time) => time + 1); // allow the time to be shown in the transition when stopping setTimeStopped((time) => time + 1); frameId = setTimeout(render, 1e3); }; frameId = setTimeout(render, 1e3); } else { setTime(0); clearTimeout(frameId); } return () => { clearTimeout(frameId); }; }, [recording]); // stop automatically if time hits limit useEffect(() => { if (time >= timeMax) { setRecording(false); } }, [time]); return (React.createElement("button", { className: "recorder", type: "button", "aria-pressed": recording, onClick: () => setRecording(!recording) }, React.createElement("span", { className: "recorder__label-start", "aria-hidden": recording }, "Stop"), React.createElement("span", { className: "recorder__switch" }, React.createElement("span", { className: "recorder__switch-handle" }, React.createElement("svg", { className: "recorder__timer", viewBox: "0 0 16 16", width: "16px", height: "16px", "aria-hidden": "true" }, React.createElement("g", { fill: "none", strokeLinecap: "round", strokeWidth: "0", transform: "rotate(-90,8,8)" }, React.createElement("circle", { className: "recorder__timer-ring", stroke: "hsla(0,0%,100%,0.3)", cx: "8", cy: "8", r: "8" }), React.createElement("circle", { className: "recorder__timer-ring", stroke: "hsla(0,0%,100%,0.5)", cx: "8", cy: "8", r: "8", strokeDasharray: strokeDashArray, strokeDashoffset: strokeDashOffset }))))), React.createElement("span", { className: "recorder__label-end", "aria-hidden": !recording }, React.createElement("span", { className: "recorder__label-end-text" }, "Record"), React.createElement("span", { className: "recorder__label-end-text" }, timeFormatted())))); }