Mobile Feed Screen — Free HTML CSS JS UI Snippet

Mobile Feed Screen · Mobile · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Gradient story rings
Unseen rings fade to grey once opened.
Double-tap to like
320ms tap timing triggers a heart burst.
Replayable burst
Reflow trick restarts the CSS animation.
Live like counts
toLocaleString keeps comma formatting correct.
aria-pressed likes
Like state exposed to assistive tech.
Save toggle
Outline star flips to filled on tap.
Bottom tab bar
Active swap with a gradient create pill.
No dependency
Pure HTML, CSS, and vanilla JavaScript.

About this UI Snippet

Mobile Feed Screen — Social Timeline UI

Screenshot of the Mobile Feed Screen snippet rendered live

A social feed is the home screen of every photo-sharing app — a horizontally scrolling row of story rings, a vertical stream of image posts with like, comment, share and save actions, and a bottom tab bar. This snippet builds a complete, interactive one inside a CSS phone frame: you can double-tap a photo to like it with a bursting heart, tap the heart to toggle the count, mark stories as seen, save posts, and switch tabs — in HTML, CSS, and vanilla JavaScript with no dependency.

The gradient story rings

Each story is a circle with a 2.5px padding that reveals a conic-style gradient ring behind an inner white disc — the recognizable "unseen story" look. Tapping a new story swaps its ring class so the vivid gradient fades to grey, exactly how real apps mark a story as watched. Your own story uses a plain grey ring, and the row scrolls horizontally with the scrollbar hidden.

Double-tap to like with a heart burst

The signature gesture is handled by timing taps on the media: two clicks within 320ms count as a double-tap, which likes the post if it is not already liked and plays a big heart-burst animation over the image. The burst is a single @keyframes mfdBurst on an overlaid heart that scales up, settles, and fades. To replay it on every double-tap, the code removes the animation class, forces a reflow with void media.offsetWidth, and re-adds it — the standard trick for restarting a CSS animation.

Live like counts

The heart button toggles a filled state and adjusts the count, parsing the displayed number by stripping commas and re-formatting with toLocaleString() so "1,284 likes" increments to "1,285" correctly. The aria-pressed attribute tracks the like state for assistive tech, and the save button flips between an outline and a filled star.

The bottom tab bar

Five tabs sit in a bar with the create button styled as a gradient pill. Tapping a tab moves the active state, and the profile tab shows a small avatar that gets a ring when active. The create button is intentionally excluded from the active-swap since it opens a composer rather than a feed section.

Accessibility and performance

Every action is a real <button> with an aria-label, and the like button carries aria-pressed that flips with its state, so screen-reader users hear whether a post is liked without relying on color. The like and save toggles change both an icon and an accent color, so the state never depends on hue alone — important for color-blind users. The double-tap gesture is layered on top of the buttons rather than replacing them, so keyboard and assistive users can still like a post by activating the heart directly. Performance-wise the heart burst is a single CSS keyframe on one overlaid element, and the restart uses a forced reflow rather than creating and destroying nodes, so rapid double-taps never leak DOM. The story row scrolls with native overflow and hidden scrollbars, which stays smooth on touch, and the count updates touch only one text node. Swapping the gradient blocks for lazy-loaded images with explicit dimensions keeps the feed from shifting as it loads.

Reusing it

Replace the gradient media blocks with real <img> elements, feed the posts from an array, and wire the actions to your API. Lift the stream out of the phone frame for a responsive web feed, or keep it framed beside a mobile profile screen to present a full app.

Build with AI

Build, Understand, Optimize, and Extend It With AI

You do not have to puzzle out the tap-timing logic on your own. Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly how the 320ms lastTap comparison distinguishes a double-tap from two separate single taps, or why the forced reflow through media.offsetWidth is necessary before re-adding the pop class to replay the mfdBurst keyframe. The same assistant is useful for optimizing it — ask whether the like-count parsing that strips commas and calls toLocaleString could break on locales that use different thousands separators, or how you would lazy-load the gradient media blocks as real images without causing layout shift in the feed. It is just as good for extending the snippet: have it add a comment sheet, a multi-image carousel per post with swipe paging, or a proper story-viewer overlay triggered from the story ring row. Treat the code less like a finished artifact and more like a starting point for a conversation.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a mobile social-feed screen in plain HTML, CSS, and JavaScript inside a phone-frame container — no framework, no gesture library.

Requirements:
- A horizontally scrolling row of story circles, each with a gradient ring around a white inner disc for unseen stories, and a plain grey ring once a story has been tapped (swap a CSS class on click, do not rebuild the element).
- One or more post articles, each with a header (avatar, username, location or timestamp, more button), a media area, an actions row (like, comment, share, save), a like-count line, and a caption.
- Detect a double-tap on the media area using only click event timestamps: record the time of each click, and if a new click lands within roughly 320 milliseconds of the previous one, treat it as a double-tap.
- A double-tap must like the post only if it is not already liked, and must always replay a heart-burst animation over the media even on repeated double-taps — implement the replay by removing the animation class, forcing a synchronous reflow by reading the element's offsetWidth, then re-adding the class.
- The like button and double-tap must share the same like/unlike logic, updating a data-liked attribute on the post, toggling the heart icon and an accent color class, updating aria-pressed, and incrementing or decrementing the displayed like count while preserving thousands-separator formatting.
- A save button that independently toggles between an outline and filled star, and a bottom tab bar where tapping a tab moves an active-state class among the tabs except for a centered create/plus tab which must not become active when tapped.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSA social feed renders with a story row, two image posts, and a bottom tab bar.
  2. 2
    Double-tap a photoTwo quick taps like the post and a large heart bursts over the image.
  3. 3
    Tap the heart buttonIt toggles filled and the like count increments or decrements with proper comma formatting.
  4. 4
    Open a storyTapping a story fades its colorful ring to grey to mark it seen.
  5. 5
    Save a postThe star button flips between outline and filled.
  6. 6
    Switch tabsThe bottom bar moves the active state; the profile tab gets an avatar ring.

Real-world uses

Common Use Cases

Social apps
The home feed behind a mobile profile screen.
Photo galleries
Style posts like an instagram gallery.
Story features
Like interactions
Reuse the burst near a like burst button.
App mockups
Present it inside a phone mockup.
Learning gestures
A reference for double-tap detection and animation restart.

Got questions?

Frequently Asked Questions

The media element records the timestamp of each tap. When a new tap lands within 320ms of the previous one, it is treated as a double-tap: the post is liked if it was not already, and the heart-burst animation plays. A single tap simply updates the timestamp and does nothing else.

CSS animations only run when the class is first applied. To replay, the code removes the pop class, reads media.offsetWidth to force a synchronous reflow, then re-adds the class. That reflow is what lets the browser register the animation as new each time, so it fires on every double-tap.

The displayed count is parsed by stripping commas and calling parseInt, then incremented or decremented, then re-rendered with toLocaleString(). That way 1,284 becomes 1,285 rather than 1284, matching how the number was originally displayed.

The plus tab opens a post composer rather than switching to a feed section, so the click handler returns early for it and leaves the current active tab in place — the same behavior as real apps where the create button launches a modal instead of a tab.

Render posts and stories from arrays and key them by id. Track liked, saved, and count in per-post state and update them in handlers rather than mutating the DOM. Replace the gradient media with img tags. For the burst, toggle an animation flag and reset it with a key change or a ref-based reflow in useEffect (React), watch (Vue), or ngAfterViewInit (Angular). Tailwind expresses the rings and gradients with utilities.