Puneet Sharma - Frontend Developer & UI Engineer
Puneet Sharma
Frontend Dev & UI Engineer · 16+ yrs · pixel-perfect HTML, React & WordPress

10 New Copy-Paste Snippets: The Everyday Patterns Every Site Still Needs

10 free HTML/CSS/JS snippets for everyday UI: off-canvas menu, EMI calculator, drag reorder list, price slider & more. No libraries, live previews.
10 New Copy-Paste Snippets: The Everyday Patterns Every Site Still Needs

Not every useful component is exotic. In between the canvas simulations and the GLB viewers, there's a much shorter list of patterns that show up on almost every site ever built: a menu that opens, a navbar that behaves on scroll, a list you can reorder, a loan number you need to compute correctly. These are the snippets developers actually paste into ChatGPT or Claude at 11pm and ask "just build me this" — and getting the small mechanical details right (a midpoint comparison, a shared transition duration, an EMI formula that doesn't divide by zero) is the difference between a demo and something you can actually ship.

Below are ten free, self-contained snippets pulled from that everyday list — navigation, forms, product UI, and layout basics — each one built without a single external library. Every one is a live, interactive preview you can try right here in the article, and each exports to React, Vue, Angular or Tailwind in one click from its snippet page.

What these ten get right

  • Two elements animating off one shared value never drift apart. The off-canvas menu's page-wrap and sidebar both animate by the same 240px and the same 0.3s transition; the magnify lens's zoomed panel and lens square both derive their position from the same x/y multiplied by the same ZOOM_FACTOR. Whenever two things need to move together, they read from one number, not two numbers that happen to agree today.
  • Ask the browser what's real instead of hardcoding a guess. The drag-and-drop list asks getBoundingClientRect() for the hovered row's actual midpoint before deciding where to insert — it never assumes a fixed row height.
  • Native browser features do the hard part for free. The price range slider is two real <input type="range"> elements layered on top of each other, not a custom-built slider — which means keyboard support, touch dragging, and screen-reader announcements all come from the browser instead of being reimplemented by hand.
  • The URL is state too. The synced tab bar treats location.hash as the single source of truth — clicking a tab and typing a hash into the address bar run through the exact same function, so refresh, bookmark, and back/forward all just work with zero router.
  • Numeric edge cases get handled, not ignored. The EMI calculator's amortization formula divides by factor - 1, which would divide by zero at a 0% interest rate — so it branches to simple division first instead of producing NaN on a perfectly reasonable input.

1. Off-Canvas Push Menu

A hamburger click doesn't slide a drawer over the page here — it pushes the entire page sideways to reveal a full-height sidebar underneath it, the pattern older Facebook and many native-feeling mobile web apps use instead of an overlay drawer.

How it works: the sidebar starts at transform: translateX(-100%), fully hidden off the left edge, while the page-wrap sits at translateX(0) on top of it. Opening the menu animates both at once — the sidebar to translateX(0), the page-wrap to translateX(240px) — using the exact same 0.3s transition duration, so the page reads as physically pushed aside by the sidebar sliding in beneath it rather than a panel sliding on top of a static page. The hamburger-to-X animation is driven off the button's own aria-expanded attribute rather than a separate class, so the visual state and the accessibility state can never fall out of sync, and three independent triggers — the close button, the scrim, and the hamburger itself — all call one shared closeMenu() function.

Best for: mobile-first app shells where a floating overlay drawer would feel disconnected from the content underneath it. Tip: the sidebar width is controlled by exactly two values that must match — .off-canvas's width and .page-wrap.shifted's translateX distance — change both together or the page will overshoot the edge or leave a gap.

Grab the code: Off-Canvas Push Menu

2. Hide on Scroll Navbar

Scroll down and the navbar slides up out of view to give the content more room; scroll back up even slightly and it slides back in immediately — the pattern most modern mobile browsers and news sites use for their own chrome.

How it works: a scroll listener compares the current window.scrollY against the value recorded on the previous scroll event to get a delta. A positive delta (scrolling down) adds a .hidden class that slides the navbar up by its own height with transform: translateY(-100%); a negative delta (scrolling up) removes it immediately. Two safeguards keep this from feeling twitchy: deltas smaller than an 8px MIN_SCROLL_DELTA are ignored entirely, so trackpad momentum-scroll jitter can't flicker the navbar in and out, and scroll positions below an 80px REVEAL_THRESHOLD always force the navbar visible regardless of direction, so it never disappears while the user is still near the very top of the page.

Best for: content-heavy pages — blogs, docs, long product pages — where reclaiming vertical space while reading matters more than a permanently pinned nav. Tip: only transform ever changes on the navbar, never top or height, which keeps the animation on the compositor thread and smooth even on longer pages.

Grab the code: Hide on Scroll Navbar

3. Drag & Drop Reorder List

A vertical task list you can physically drag into a new order, with a live insertion line that shows exactly where the item will land — built entirely on the browser's native HTML5 Drag and Drop API, no sortable-list library involved.

How it works: every list item has draggable="true", and a single set of dragstart/dragover/drop/dragend listeners on the list container — not one per item — resolves the actual row with e.target.closest('.item'). The interesting part happens on dragover: target.getBoundingClientRect() gives the hovered row's real position, and comparing the cursor's e.clientY against that row's vertical midpoint decides whether to draw the insertion line above or below it, updating continuously as the cursor moves. On drop, the same midpoint check runs once more, then insertAdjacentElement('beforebegin' | 'afterend', draggedItem) physically relocates the real dragged node — not a clone — so nothing attached to that element is ever lost.

Best for: task lists, playlists, and priority queues where users need to manually resequence items and you'd rather not ship a sortable-list dependency for it. Tip: native HTML5 drag-and-drop has inconsistent touch support — for a mobile-friendly version, swap to Pointer Events and track the drag position manually instead.

Grab the code: Drag & Drop Reorder List

4. Swipeable Cards Stack

A Tinder-style stack where the top card drags left or right under your cursor, rotates as it goes, and flies off-screen past a threshold to reveal the next card underneath — pure Pointer Events, no gesture library.

How it works: pointerdown checks that the card being pressed is actually the current top card via getTopCard() before capturing the pointer, so cards buried in the stack never intercept a drag meant for the one on top. As the pointer moves, currentX and currentY track the offset from the start position, and a rotation of currentX / 12 degrees is applied alongside the translation — the further sideways the drag, the more the card tilts, mimicking the way a real card would pivot under a finger. On release, if |currentX| cleared a 100px SWIPE_THRESHOLD, finishSwipe() adds a .fly-left or .fly-right class that flings the card off-screen with a CSS transition and removes it from the DOM on transitionend; otherwise the card's inline transform is simply cleared, springing it back to center.

Best for: matching/dating-app UIs, quick approve-or-reject review queues, and onboarding flows that want a tactile, gesture-driven decision moment instead of a plain button pair. Tip: the accept/reject buttons call the exact same finishSwipe() function as a real drag — useful for keyboard or screen-reader users who can't perform the gesture themselves.

Grab the code: Swipeable Cards Stack

5. Product Image Magnify Lens

An Amazon-style zoom: hover the product photo and a small lens square follows your cursor while an adjacent panel shows a magnified view of exactly the region under it — pure CSS background-position math, no canvas.

How it works: a mousemove listener computes the cursor's position relative to the image container from getBoundingClientRect(), then clamps it with Math.max(0, Math.min(...)) so the lens can never slide past the image's own edges. The zoom panel is a completely separate element carrying the same background image, scaled up via background-size set to the container's dimensions multiplied by a single ZOOM_FACTOR constant, then shifted into place with background-position set to the negative of the lens coordinates — also multiplied by that same ZOOM_FACTOR. Because the lens position and the zoomed background-position both derive from the same x/y and the same scaling constant, the magnified view always shows precisely what's under the lens instead of drifting out of alignment as the cursor moves.

Best for: e-commerce product pages where fine detail — fabric texture, stitching, screen resolution — genuinely needs a closer look than a normal-sized photo provides. Tip: swap the CSS gradient placeholder for a real high-resolution product photo — the technique needs the source image to actually contain more detail than the base display size shows, or the zoom will just look blurry.

Grab the code: Product Image Magnify Lens

6. Price Range Slider

A dual-handle slider for filtering by min and max price — built from two real, overlapping native range inputs rather than a custom-built widget, so keyboard support and touch dragging come free from the browser.

How it works: two <input type="range"> elements sit stacked exactly on top of each other, each with a transparent, non-interactive track (pointer-events: none) but a fully interactive thumb (pointer-events: auto on the ::-webkit-slider-thumb pseudo-element) — so clicking the invisible track does nothing, but dragging either visible circular handle works normally, and the two inputs never fight over the same click. A separate .range-fill div, not part of either input, is positioned between the two thumbs by converting both values to percentages of the max and setting left/width accordingly on every input event. Since nothing stops one native range input from crossing past its sibling on its own, updateSlider() checks whether the gap between values has dropped below a minimum threshold and, if so, pushes the other slider's value back to maintain it — using this to know which slider just fired and which one to leave alone.

Best for: e-commerce filter sidebars, marketplace search filters, and any "between X and Y" numeric filter where a plugin feels like overkill for two inputs and a fill bar. Tip: because both inputs are real <input type="range"> elements, arrow keys, Page Up/Down, and screen-reader value announcements all work without any extra code.

Grab the code: Price Range Slider

7. Tabs with URL Sync

A tab bar whose active tab lives in location.hash, so refreshing the page, sharing a direct link, and clicking browser back/forward all land on the correct panel — no router needed.

How it works: clicking a tab doesn't toggle classes directly — it calls goToTab(tabName), which does nothing more than set location.hash = tabName. Setting the hash triggers the browser's native hashchange event, which runs readHashAndActivate() to read the hash back out and update the visible tab and panel. That means clicking a tab in the UI and typing a hash straight into the address bar go through the exact same code path — the hash is the only source of truth, never a separate JS variable that could fall out of sync with the URL. Because every hash assignment pushes a new browser history entry automatically, back and forward buttons walk through tab history for free, with zero manual history.pushState bookkeeping.

Best for: documentation pages, settings screens, and any tabbed content worth deep-linking or bookmarking directly to a specific section. Tip: readHashAndActivate() falls back to a default tab name whenever the hash doesn't match a known value, so a mistyped or stale link never leaves the UI in a blank state.

Grab the code: Tabs with URL Sync

8. Loan EMI Calculator

Type a loan amount, interest rate, and tenure and get an instant monthly installment, total interest, and total payment — using the real amortization formula lenders use, not a rough approximation.

How it works: the monthly installment is computed with the standard EMI formula, P × r × (1+r)^n / ((1+r)^n − 1), where P is principal, r is the monthly interest rate, and n is the number of months — the same formula banks use for amortized loans. That formula divides by (1+r)^n − 1, which collapses to zero at a 0% interest rate and would produce NaN; the calculator checks for that case first and falls back to simple division (principal / months) instead, so a perfectly reasonable interest-free loan doesn't break the display. Total interest is derived as totalPayment − principal, clamped to zero with Math.max so floating-point rounding can never show a tiny negative number, and a two-segment bar visualizes the principal-to-interest ratio by converting both to percentages of the total payment.

Best for: mortgage and auto-loan estimator pages, fintech onboarding flows, and personal-finance tools where users need to see the real cost of interest before committing. Tip: every input fires calculateEmi() on oninput, so the results and the principal/interest bar update live as the user types — there's no separate "Calculate" button to wire up.

Grab the code: Loan EMI Calculator

9. Feature Comparison Matrix Table

A pricing table shaped like a real feature matrix — plan columns, feature rows, checkmark and cross icons, and one visually highlighted "recommended" column running the full height of the table.

How it works: every cell in the recommended plan's column — header and body alike — shares a single .recommended class that applies a tinted background plus matching left and right borders. Because every cell in that column carries the same class, the tinted background and borders line up perfectly row after row, reading as one continuous highlighted band running down the table rather than a set of separately-styled cells that happen to match. The included/excluded state per feature uses real inline SVG checkmark and X icons rather than styled bullet characters, colored through a shared .cell-icon.yes/.cell-icon.no class rather than being hardcoded per icon — so changing the "included" color in one place recolors every checkmark in the table.

Best for: SaaS pricing pages, plan-comparison landing sections, and any "which tier do I need" decision point where a simple three-card pricing layout doesn't have room for feature-level detail. Tip: the table is fully static HTML by design — if your plans and features come from a CMS or config file, generate the exact same markup structure server-side or in a small render function rather than hand-writing each row.

Grab the code: Feature Comparison Matrix Table

10. Recent Purchase Notification Popup

A "social proof" toast that periodically slides in from the bottom corner showing a recent purchase, auto-dismisses after a few seconds, then cycles to the next one — the classic FOMO widget pattern, built from one array and two timers.

How it works: a small array of notification objects (name, location, product, timestamp) is the entire data source — renderNotification() just writes the current entry's fields into the toast's DOM nodes before it's revealed. showToast() adds a .visible class that slides the toast in with a cubic-bezier transition and starts a VISIBLE_DURATION timer that calls hideToast(false) automatically; hideToast() advances index to the next notification with (index + 1) % NOTIFICATIONS.length — wrapping back to the start once the array is exhausted — and schedules the next showToast() after a gap. Dismissing the toast manually versus letting it auto-hide both funnel through the same hideToast(userDismissed) function, which only differs by using a longer gap before the next notification when the user closed it themselves, so an annoyed visitor gets a bit more breathing room before the next one appears.

Best for: e-commerce storefronts and landing pages that want a subtle, non-blocking sense of live activity. Tip: the entire cycle is driven by two setTimeout calls and one array — swapping the hardcoded array for a small polling fetch() against a real "recent orders" endpoint requires no changes to the show/hide/cycle logic at all.

Grab the code: Recent Purchase Notification Popup

How to drop these into your project

  1. Open any snippet and hit View / Edit Code to see the HTML, CSS and JS in separate tabs, then paste the HTML into your markup, the CSS into your stylesheet, and the JS before your closing </body> tag — or use the one-click export to React, Vue, Angular or Tailwind right from the snippet page. Every snippet in this batch needs nothing installed at all — no CDN scripts, no npm packages.
  2. When two elements must move together, drive both from one shared value. The off-canvas menu's page-wrap and sidebar, and the magnify lens's zoom panel and lens square, are the pattern to copy: pick one number (a distance, a scroll fraction, a cursor coordinate), derive every visual consequence from that same number, and the pieces can never drift out of sync with each other.
  3. Reach for the browser's native input before building a custom widget. The price range slider gets keyboard support, touch dragging, and screen-reader announcements for free by using two real <input type="range"> elements instead of a fully custom-built slider — that's usually the right default until a native element genuinely can't do what you need.
  4. Handle the numeric edge case, don't just hope it never happens. The EMI calculator's zero-interest branch and the drag list's midpoint clamp both exist because someone will eventually hit that exact input — test your own calculations and coordinate math against the boundary values (zero, the exact edge, the exact midpoint) before shipping.
  5. In React, Vue, or Angular, event listeners move into mount effects with real cleanup. The scroll listener behind the hiding navbar, the pointer listeners behind the swipeable cards, and the hashchange listener behind the URL-synced tabs all need to be attached once on mount and explicitly removed on unmount — each snippet's FAQ section spells out exactly what that cleanup should look like.

Final thought

None of these ten needed a library. A menu that pushes instead of overlays, a navbar that reads scroll direction, a slider built from two native inputs, a calculator that handles its own zero case — the pattern across all of them is reaching for what the platform already gives you (transforms, native range inputs, location.hash, getBoundingClientRect) and adding just enough JavaScript to coordinate it. That's usually less code than the library would have shipped, and it's code you actually understand well enough to debug at 11pm when something's slightly off.

Try them, retune the constants, and export to your framework of choice in one click. Browse the full collection at FWD Tools UI Snippets — it's free and runs entirely in your browser.

About the author

Puneet Sharma
Puneet Sharma is a freelance web developer and the creator of FWD Tools and WebDevPuneet. Follow him on X/Twitter

Post a Comment