Mocking up an app idea usually means one of two bad options: wire up a real native project just to test whether a flow feels right, or drop static boxes into Figma that can't actually be clicked, typed into, or swiped. Neither answers the question that actually matters, which is whether the interaction feels good — whether the double-tap registers cleanly, whether the checkout math updates instantly, whether the onboarding carousel tracks a swipe convincingly. Below are 10 free mobile app screens you can preview live and copy in seconds: onboarding, login, a lock screen, a social feed, a stories viewer, a chat thread, a music player, a fitness dashboard, a banking home screen, and a checkout — enough to walk a whole app concept from first launch to paid order.
Each one comes with how it actually works, when to reach for it, and a tip for adapting it. They're all plain HTML, CSS, and vanilla JavaScript — no native framework, no build step — rendered inside a realistic CSS phone frame with a working status bar, so a screenshot of the embed already looks like a device mockup.
Every snippet below is a live, interactive preview — swipe the onboarding, drag the seek bar, watch the totals recalculate, right in the article. When you find one you like, hit View / Edit Code to grab the HTML/CSS/JS or export it to React, Vue, Angular or Tailwind.
What actually makes a mobile mockup feel real
Three ideas run through every screen below, and they're worth naming because they're what separates a screen that looks like an app from one that behaves like a picture of an app:
- One function owns each piece of derived state. The checkout's
recalc(), the onboarding'sgo(i), the fitness rings' per-ring circumference math — each screen routes every interaction that changes a number or a position through a single function, so the UI can never show two numbers that disagree with each other. - Motion confirms the action, not just decorates it. A heart that bursts on double-tap, a vinyl disc that only spins while playing, a progress bar that visibly fills before it auto-advances — each animation is reporting a state change, which is what makes tapping something feel like it worked.
- Real form controls under the hood. Radio buttons for payment methods, a real
<form>for chat and login, disabled states on buttons that shouldn't be tappable yet — the phone-frame chrome is cosmetic, but the interactive elements underneath are genuine, focusable, accessible DOM.
Keep those three in mind as you scroll — they're also exactly what to check for if you're evaluating whether a mockup is ready to hand to a developer.
1. Mobile Onboarding Screens
The swipeable intro carousel every app shows on first launch: three feature slides with morphing blob illustrations, a worm-style animated progress indicator, a skip button, and a context-aware final screen.
How it works: every slide sits in a flex track at min-width: 100%, and moving between them is a single transform: translateX(-index * 100%) on the track — there's no per-slide show/hide, just one number changing and CSS animating the rest. A single go(i) function is the only thing allowed to touch that index: the Next button, the Skip button, and a pointer-swipe gesture (comparing the start and end clientX against a 45px threshold) all call it, so the slide position, the progress dots, and the button label can never drift out of sync with each other. The dots use the "worm" style — the active one stretches from a small circle into a pill via a CSS transition rather than just changing color — and on the last slide, Next relabels itself "Get started" while Skip hides, since skipping the final screen makes no sense.
Best for: the very first screen of any app pitch or prototype. Tip: keep the slide count at three or four — a single go() function scales to any number, but attention for an intro carousel drops off fast past four screens.
Grab the code: Mobile Onboarding Screens
2. Mobile Login Screen
A complete sign-in flow: branding, real inline email and password validation, a password show/hide toggle, a loading submit state, and social buttons.
How it works: submitting the form runs the email through a pragmatic regex and the password against a minimum length, and a failing field gets a red border plus a message that specifically distinguishes "Email is required" from "Enter a valid email address" — generic errors are worse than no error, because they don't tell anyone what to fix. The error clears the moment the field is edited again, so the form guides rather than nags. The reveal button is the standard accessible pattern: it flips the input's type between password and text and updates its own aria-label to match, rather than duplicating the field. On a valid submit, the button enters a disabled-looking loading state with a changed label before confirming — the exact seam where a real auth call belongs.
Best for: any app's entry point, and a solid reference for form validation UX generally. Tip: lift the form out of the phone frame entirely and it works as a responsive web login — nothing in the validation logic depends on the device chrome around it.
Grab the code: Mobile Login Screen
3. Mobile Lock Screen
The first thing a phone shows: a live clock and date, a stack of frosted-glass notifications that cascade in, and a real swipe-up-to-unlock gesture.
How it works: a tick() function reads the real system clock, formats a 12-hour time and a full weekday-plus-month date from raw Date fields — not a locale shortcut — and keeps it current on an interval, so the lock screen never looks frozen on a placeholder. The notification cards use genuine glassmorphism: a translucent background layered with backdrop-filter: blur(10px) over the gradient wallpaper, entering with a staggered fade-and-slide keyframe so the stack cascades rather than popping in at once. Unlocking works two ways — clicking the grip, or an actual gesture, where pointerdown records a starting Y and pointerup only fires the unlock if the pointer moved up more than a 60px threshold, the same threshold-based swipe detection used for dismissible sheets.
Best for: app concept pitches and push-notification design, where showing the lock screen first sells the idea before anyone opens the app. Tip: the wallpaper is a pure CSS gradient — swap the colors to match a brand in one edit, no image asset required.
Grab the code: Mobile Lock Screen
4. Mobile Feed Screen
A social timeline: a horizontally scrolling story row, image posts with double-tap-to-like and a bursting heart, live like counts, and a bottom tab bar.
How it works: the signature gesture is timing-based — a click on the media area records a timestamp, and if a second click lands within 320ms it counts as a double-tap, liking the post if it isn't already liked and replaying a heart-burst animation over the image. Replaying that animation on every double-tap (not just the first) needs a specific trick: the code removes the burst's CSS class, forces a synchronous reflow by reading offsetWidth, then re-adds the class — the standard way to restart a CSS animation that's already run once. The like count is parsed by stripping commas, incremented, and re-formatted with toLocaleString(), so "1,284 likes" correctly becomes "1,285" instead of "1284". Story rings fade from a vivid gradient to grey the moment they're tapped, exactly how real apps mark a story seen.
Best for: any social or photo-sharing app's home screen. Tip: the double-tap gesture is layered on top of the like button, not instead of it — keep both so keyboard and assistive-tech users have a direct way to like a post.
Grab the code: Mobile Feed Screen
5. Mobile Stories Viewer
A full-screen, self-driving slideshow: segmented progress bars that fill one at a time, tap zones to jump forward or back, hold-to-pause, and a reply bar.
How it works: each segment's fill is a four-second CSS keyframe animation — there's no setInterval counting milliseconds anywhere. The browser owns the timing entirely; JavaScript only listens for the fill's animationend event and advances to the next slide when it fires, which keeps the story precisely in step with what's visually on screen. Two invisible buttons cover roughly the left and right third of the stage for previous and next, and navigating to any slide restarts its bar from zero using the same clear-reflow-reapply trick as the feed screen's heart burst. Hold-to-pause is pure CSS state: a pointerdown anywhere on the stage sets the active bar's animation-play-state to paused, which freezes the fill exactly where it is and resumes from that same point on release — no elapsed-time bookkeeping required.
Best for: the natural next screen after a feed, or as a lighter, punchier alternative to a full onboarding carousel for a single feature highlight. Tip: the CSS-timed approach means pacing is trivial to change per slide — just vary that one keyframe's duration.
Grab the code: Mobile Stories Viewer
6. Mobile Chat Screen
A messaging thread: two-sided bubbles with CSS-only tails, an animated typing indicator, read-receipt ticks, and a composer that won't send blank messages.
How it works: incoming and outgoing messages share one bubble class and flip alignment purely through their row's flex justification — the "tail" is faked entirely with border-radius, fully rounding three corners and cutting the fourth to a small radius, opposite corners for each direction, so there's no SVG or image involved anywhere. The composer is a real <form>, so pressing Enter submits, and the send button is disabled whenever the trimmed input is empty, re-enabling as you type. On submit, the message appends with a short pop-in animation, the thread scrolls to the bottom via scrollTop = scrollHeight, and a staggered three-dot typing indicator shows before a canned reply lands — the exact two cues real chat apps give while the other side is composing.
Best for: messaging apps, support widgets, or styling an AI assistant's response thread. Tip: swap the setTimeout reply for a WebSocket handler and the rest of the UI — bubbles, scroll, typing indicator — needs no changes at all.
Grab the code: Mobile Chat Screen
7. Mobile Music Player Screen
A full-screen now-playing view: a spinning vinyl disc that only turns while playing, a draggable seek bar, a real elapsed-time clock, and mode toggles.
How it works: a single render() function is the only place that reads the elapsed seconds and writes the progress fill's width, the knob's position, and the formatted m:ss label — so those three outputs can never disagree. Play starts a one-second interval that advances the clock and calls render(); a class toggle on the album art flips the vinyl disc's rotation animation between paused and running, so it freezes and resumes from exactly where it stopped with zero extra JavaScript. The seek bar supports both a click-to-jump and a real knob drag using Pointer Events — the drag listens on window, not just the track, so the gesture keeps working even if the pointer slides off the bar mid-drag, and the resulting ratio is clamped to stay within 0 and 1.
Best for: the now-playing screen behind a mini-player bar, or as a scrub-bar reference for any timed media UI. Tip: swap the setInterval clock for a real <audio> element's timeupdate event and the render function needs no changes — only the time source moves.
Grab the code: Mobile Music Player Screen
8. Mobile Fitness Screen
An activity-tracker home screen: three concentric SVG progress rings that sweep up from empty on load, a stat grid, and a workout history list.
How it works: each ring is an SVG circle whose progress is drawn with the classic stroke-dasharray/stroke-dashoffset technique — the dash length is set to the circle's own circumference (2Ï€r), and the offset shrinks toward zero to reveal more of the arc, rotated -90 degrees so it starts at twelve o'clock like a real wearable. Because the three rings have different radii, each needs its own circumference computed independently — sharing one value across all three would misalign the inner arcs at the same percentage. On load, the rings start fully offset, then a double requestAnimationFrame sets the real target offset on a later frame, which is what makes the browser register a genuine transition from empty to filled instead of just painting the final state instantly.
Best for: fitness and health apps, or any goal-tracking UI that wants the "closing your rings" moment. Tip: the legend beside the rings already spells out each metric in text — treat that as the accessible source of truth and mark the decorative SVG aria-hidden.
Grab the code: Mobile Fitness Screen
9. Mobile Banking Screen
An account dashboard: a gradient balance card styled like a physical payment card, a hide-balance toggle that blurs every amount at once, a quick-action grid, and a color-coded transaction list.
How it works: the privacy toggle is the detail worth studying — tapping the eye flips one shared hidden class across the balance and every transaction amount on the page, and that class doesn't replace the digits with dots, it sets their color to transparent and layers a soft text-shadow blur. The real numbers stay in the DOM the whole time, they just render as an unreadable smudge, which makes revealing them instant with no re-render — and income versus spending rows keep tinted blur shadows so the row's type is still hinted even while redacted. The balance card itself fakes a physical card with a large faded circle bleeding off one corner via an ::after pseudo-element, layered behind the content with z-index. Quick-action taps get a tactile pulse from the Web Animations API (element.animate()) rather than a permanent state change, which is the right call for buttons that would navigate elsewhere in a real app.
Best for: fintech and banking apps, or anywhere a screen needs a genuine privacy affordance. Tip: when you adapt this, also swap the accessible text while hidden — an aria-label like "balance hidden" — since the blur is purely visual and a screen reader would otherwise still announce the real figure.
Grab the code: Mobile Banking Screen
10. Mobile Checkout Screen
The final step: an address card, cart items with quantity steppers, custom-styled payment radios, a working promo code, and a live-recalculating order summary under a sticky pay button.
How it works: every cart item stores its unit price on a data-price attribute, and a single recalc() function is the only place any total gets computed — it walks the items, multiplies price by quantity, applies the current discount rate, adds flat shipping, and writes the subtotal, discount line, grand total, and the sticky bar's total all from that one pass. Every interaction that could change the total, whether a stepper tap or a promo code, calls this same function, which is what keeps the summary and the sticky bar from ever showing two different numbers. The minus stepper deliberately won't drop a quantity below one — that's a guard forcing an explicit remove action instead of an ambiguous zero. The promo code uppercases the input before comparing it, so "save10" and "SAVE10" both work, and gives three distinct states: applied, invalid, and empty, each with its own message.
Best for: the final screen of any commerce flow, and a solid reference for centralizing totals instead of nudging a running number. Tip: the payment methods are genuine radio inputs styled with a :checked ~ sibling selector, not divs with click handlers — keep that pattern, since it gives keyboard and screen-reader selection for free.
Grab the code: Mobile Checkout Screen
How to drop these into your project
Every snippet is framework-agnostic, so the workflow is the same wherever you're building:
- Open the snippet and hit View / Edit Code to see the HTML, CSS and JS in separate tabs.
- Paste the HTML into your template, the CSS into your stylesheet, and the JS before your closing
</body>tag — none of these ten need a CDN script or a build step. - Prefer a component? Use the one-click export to React, Vue, Angular or Tailwind right from the snippet page.
- Keep or discard the phone frame independently — every screen's real content works lifted out as a responsive web layout, since the frame is a wrapper, not a dependency.
- Replace the seeded data — messages, transactions, workouts, cart items — with your real data, and wire each screen's central function (
recalc(),render(),go()) to update whenever that data changes.
A few mobile-UI principles worth keeping
- Route every derived value through one function. The checkout's totals, the fitness rings' offsets, the music player's progress bar — each is written by exactly one function, which is what makes them trustworthy under rapid interaction.
- Let CSS own timing wherever it can. The stories viewer's auto-advance and the music player's vinyl spin both hand timing to the browser's animation engine instead of a JavaScript timer, which is both simpler code and a smoother result.
- Redact without destroying data. The banking screen's blur-not-replace approach to hiding numbers is a broadly useful pattern anywhere sensitive data needs an instant, reversible hide.
- Confirm every tap. A bursting heart, a pulsing icon, a flashing row — the fastest way to make an interface feel responsive is to never leave a tap without a visible reaction.
Final thought
These ten cover a full app arc: launch into onboarding, sign in, land on a lock screen or straight into a feed, open a story or a conversation, play something, check your stats or your balance, and check out. Start with whichever screen matches the app you're actually building — the login screen and the checkout are the two almost every app eventually needs regardless of category.
Preview any of them live, tweak the code, 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.
