
CSS Submit Button (Form Primary)
outline plus a soft halo so it survives on any background. Zero JavaScript, four states, one token block.Published
51 copy-paste CSS buttons for submit forms, primary and secondary CTAs, ghost and outline variants, icon-only with accessible tooltips, gradient CTAs, loading spinners, disabled references, button groups, state machines (add-to-cart, download, play/pause), hover effects, click animations (ripple, glitch, ink spread), and material studies (brass, walnut, aged copper with @property patina). Scoped under .cb-NN, prefers-reduced-motion guarded, framework-agnostic.
Related20 CSS Loading Buttons36 CSS Button Hover Effects20 CSS Animated Buttons

outline plus a soft halo so it survives on any background. Zero JavaScript, four states, one token block.Published

Published

background-size transition on a gradient — no pseudo-element, no overflow clipping, and the border is drawn in currentColor so a single colour change re-skins everything.Published
@starting-style and is positioned with CSS anchor positioning, falling back to a plain absolute offset.Published

@property registers the angle as an <angle> type — plain custom properties cannot be animated.Published

stroke-dashoffset, and the state lives in a single data-state attribute mirrored to aria-busy and a live region.Published

disabled, and aria-disabled (focusable, explains itself, refuses activation). The hover/focus/pressed cards are frozen with state classes so you can compare all six simultaneously instead of chasing a pointer.Published

:has(), and the active label crosses over the thumb by inverting colour at the same moment.Published

PublishedUpdated

role="progressbar" so the value is exposed, not implied.PublishedUpdated

PublishedUpdated

PublishedUpdated

clip-path: polygon() with the same point count, so the browser interpolates every vertex; a progress ring sits around it and the whole thing is a single checkbox.PublishedUpdated

PublishedUpdated

PublishedUpdated

clip-path and pushed apart in cyan and magenta. Steps-based timing keeps it digital — no easing, no blur, no JavaScript.PublishedUpdated

text-shadow and box-shadow rather than a blur filter, so it stays crisp at any zoom, and the plasma is a registered-angle conic gradient under a blur.PublishedUpdated

PublishedUpdated

PublishedUpdated

animationend so the DOM never grows.PublishedUpdated

PublishedUpdated

PublishedUpdated

backdrop-filter blurs and desaturates whatever is behind it, a bright inner rim catches the light on two edges only, frost bloom collects in the corners, and pressing sends a hairline crack across the face.PublishedUpdated

PublishedUpdated

PublishedUpdated

PublishedUpdated

preserve-3d, backface-visibility — and a checkbox holding the state, so no JavaScript is involved.PublishedUpdated

aria-live region, so the message is announced rather than merely displayed. Press again to reset.PublishedUpdated

PublishedUpdated

clip-path, and a press that drops the slab into its own shadow with a puff of dust at the base.PublishedUpdated

PublishedUpdated

mask-composite, an inner top-light, a spring lift on hover, a shortcut chip that dims as the arrow slides, and a focus ring that respects the pill's radius exactly.PublishedUpdated

PublishedUpdated

clip-path, near-black translucency over a blurred backdrop, two facet planes shaded by overlapping gradients, and a razor of light that runs along the leading edge on hover.PublishedUpdated

PublishedUpdated

PublishedUpdated

:has(:checked) 3D rotation.PublishedUpdated

PublishedUpdated

PublishedUpdated

filter transition, exactly how the chemistry actually behaves. The frame tilts, lifts off the table, and the caption is hand-written on the wide bottom border.PublishedUpdated

tabular-nums so nothing shifts as they change.PublishedUpdated

PublishedUpdated

PublishedUpdated

:has() drives the rotation.PublishedUpdated

PublishedUpdated

PublishedUpdated

PublishedUpdated

aria-pressed, not just its look.PublishedUpdated

counter-reset and printed through content. Zigzag torn bottom edge, faded thermal ink, monospaced columns.PublishedUpdated

PublishedUpdated

PublishedUpdated
Tweak the exact look in our visual generators — no signup, instant copy-paste.
button element with type='submit' inside a form element — never a div or an a with a click handler. Style it with padding, a solid background or gradient, border-radius, font-weight, and cursor pointer. Add :hover and :active states with a transition so the change is smooth, and a :focus-visible outline so keyboard users can see focus. Set a minimum touch target of 44×44px so mobile taps hit reliably. Demo 01 in this collection (CSS Submit Button (Form Primary)) ships the full recipe including aria-busy handling for the loading state — open the code panel to copy.aria-label on the button describing the action (aria-label='Delete file'). Second, use the native Popover API for the tooltip: put popover on a sibling element and popovertarget on the button — the browser handles focus, ESC-to-dismiss, and light-dismiss for free. Third, link them with aria-describedby so screen readers announce both the label AND the tooltip content. Demo 04 (Icon-Only Button with Accessible Tooltip) ships this pattern with a CSS-anchor-positioning fallback for browsers without Popover support.data-state attribute: idle → loading → success → reset. Each state is a CSS rule that shows or hides layered spans inside the button — label, spinner, checkmark. On click, toggle data-state='loading' and set aria-busy='true', then after the async work completes swap to data-state='success' and aria-busy='false'. Common pitfalls: use aria-disabled='true' instead of the disabled attribute so the button stays focusable during loading (users can tab away), announce the state to screen readers via a polite live region, and add pointer-events: none to prevent double-clicks. Demo 06 (Loading Spinner Button) ships the full recipe in 18 lines of JS. elements inside a fieldset with role='group' on a wrapper — this gives you keyboard arrow-key navigation for free, exclusive selection, and screen-reader semantics. Visually hide the radios with a clip-path pattern (not display: none which removes them from the tab order), then style the sibling elements as segments. Use :has() on the wrapper to style the group when any radio is checked, with an @supports not selector(:has(*)) fallback for older browsers. Demo 08 (CSS Button Group Component) ships the pattern with arrow-key nav and dark-mode support.disabled attribute grays out the button AND removes it from the tab order — use for form validation errors where the disabled state is temporary. aria-disabled='true' visually disables but keeps focus and Space/Enter — pair with pointer-events: none and a JS handler that ignores clicks, use for pending async operations where users need to tab past. Style both with opacity: 0.5 and cursor: not-allowed, and never disable the ONLY action on a screen (offer a why-disabled tooltip instead). Demo 07 (Disabled Button State Full Reference) shows every state side-by-side: default, hover, focus, active, disabled, loading.bg-*, hover:*, focus:ring-* — great for design-system patterns, but the utility system doesn't extend to conic-ring hold-to-confirm, gooey SVG filters, magnetic cursor-follow, mercury ripples, or 31 material studies (brass letterpress, frosted ice, velvet, IBM punch card). For those you write custom CSS anyway. shadcn/ui and Material UI ship pre-styled button components with variant slots — excellent for design systems, but they don't include the material studies or click-effect studies in this collection. The 51 demos here ship raw so you can lift a technique and drop it into React, Vue, Svelte, Astro, or plain HTML with zero adaptation. Copy the CSS, wrap the interaction in your framework's event handlers, done.15 mouse-aware 3D tilt hover cards — e-commerce product spotlight, glassmorphism parallax team card, interactive pricing tier, holographic NFT collectible, pop-out mascot, dark tech grid with border glow, media player album art, blog article preview, cyberpunk neon glow, dashboard KPI widget, minimalist real estate, flip-to-back tilt, mobile app showcase, course learning card, and a Pure CSS touch-friendly tilt. Vanilla JS writes --rx/--ry/--mx/--my; all rendering stays in CSS on the GPU.
24 hand-coded CSS animated card patterns organised by what triggers the motion, not by card style. Scroll and entrance triggers: staggered grid reveals, @starting-style mount-in, scroll-driven scale and fade on animation-timeline: view(), View Transitions API card-to-detail morphs, blur-to-sharp lazy image loading, and FLIP re-layout when a filter changes. State-change triggers: add-to-cart success morph, like and save particle burst, expand and collapse to intrinsic height with calc-size(), swipe-to-dismiss on Pointer Events, and skeleton-to-loaded crossfade. Data-driven triggers: count-up KPI metrics, SVG sparkline draw-on-enter, and progress ring fill on load. Ambient idle loops: breathing glow, floating drift, animated gradient mesh backgrounds, conic rotating borders, auto-cycling testimonial decks, and live status pulses. Plus four hover patterns where the effect is the topic itself: cursor spotlight, holographic foil glare, corner ribbon slide, and horizontal accordion expand. Every card is scoped under a .ac-NN prefix for no-collision pasting, guards prefers-reduced-motion, animates compositor-only properties, and ports unchanged to React, Vue, Svelte, Astro, Next.js and Tailwind.
22 hand-coded CSS avatars for chat apps, team dashboards, comment threads, account menus, and social profiles. Covers circular and squircle shapes, gradient and conic story rings, hexagon clip-path crops, online status dots, notification count badges, verified checkmarks, stacked facepiles with plus-N overflow, initials fallbacks for users without photos, broken-image recovery, avatar pickers, and a size scale system where the ring, badge, and status dot all scale from a single custom property.