Mobile Feed Screen — Free HTML CSS JS UI Snippet
Mobile Feed Screen · Mobile · Plain HTML, CSS & JS · Live preview
What's included
Features
About this UI Snippet
Mobile Feed Screen — Social Timeline UI

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