Perceived performance
Also called perceived speed or perceived load time
How fast an app feels to people, which skeleton screens, instant feedback, and progressive loading can improve even when the real wait stays the same.
import { useEffect, useState } from 'react';
import { motion } from 'motion/react';
const PAGE_SIZE = 4;
const SKELETON_DELAY_MS = 300; // fast responses skip the loading state
type Post = { id: string; author: string; text: string; avatar: string };
// Posts stream in one by one while `loading` is true. Skeleton rows hold the
// final layout, and each real row fades in at the same size, so nothing jumps.
export function Feed({ posts, loading }: { posts: Post[]; loading: boolean }) {
const [slow, setSlow] = useState(false);
useEffect(() => {
if (!loading) return;
const timer = setTimeout(() => setSlow(true), SKELETON_DELAY_MS);
return () => {
clearTimeout(timer);
setSlow(false);
};
}, [loading]);
const placeholders =
loading && slow ? Math.max(PAGE_SIZE - posts.length, 0) : 0;
return (
<ul aria-busy={loading} className='flex w-80 flex-col gap-2'>
{posts.map((post) => (
<motion.li
key={post.id}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.2 }}
className='flex h-16 items-center gap-3 rounded-xl border px-3'
>
<img src={post.avatar} alt='' className='size-10 rounded-full' />
<div className='min-w-0'>
<p className='text-sm font-medium'>{post.author}</p>
<p className='truncate text-sm text-muted-foreground'>
{post.text}
</p>
</div>
</motion.li>
))}
{Array.from({ length: placeholders }, (_, i) => (
<li
key={`skeleton-${i}`}
aria-hidden
className='flex h-16 animate-pulse items-center gap-3 rounded-xl border px-3'
>
<div className='size-10 rounded-full bg-muted' />
<div className='flex flex-col gap-2'>
<div className='h-3 w-24 rounded bg-muted' />
<div className='h-3 w-44 rounded bg-muted' />
</div>
</li>
))}
</ul>
);
}Replace the full-page spinner on the feed with a skeleton screen that matches the real layout: gray blocks for the avatar, name, photo, and two text lines. Fill in each part as soon as its data arrives, fade content in over 200ms, keep the same sizes so nothing shifts, and show no loading state at all if the data arrives within 300ms.
Paste into Layerwise or any AI coding tool.
What is Perceived performance?
Perceived performance is the speed people feel, which can differ a lot from the speed a stopwatch measures. A blank screen with a spinner makes every second noticeable. A screen that shows its layout right away and fills in piece by piece feels faster, even when the content finishes loading at the same moment.
Common techniques: respond to every tap within about 100ms, show a skeleton screen shaped like the real content, load the most important part first, use optimistic UI so actions look done before the server confirms, and keep animations short so they never add to the wait.
These techniques work alongside real speed. Keep measuring actual load times, give skeletons the same size as the final content so nothing jumps when it arrives, and skip the loading state for anything that finishes within about 300ms, where a quick flash of a spinner feels slower than showing nothing.
Often confused with
- Skeleton screen
- A skeleton screen is one technique for improving perceived performance. Perceived performance is the overall goal of making waits feel shorter.
Related terms
All termsSkeleton screen
A loading placeholder made of gray blocks shaped like the content on its way, often with a soft shimmer, that the real content replaces.
Optimistic UI
A pattern where the interface shows the result of an action right away, before the server confirms it, and rolls it back if the request fails.
Loading state
The view a screen shows while its data is on the way, designed together with the outcomes that follow: loaded, empty, or error.
Spinner
A small looping animation, usually a rotating ring, that shows the app is busy with a short task of unknown length.
Build it with Layerwise
Describe your app, watch it run in a live preview, and publish it with a database, storage, and sign-in built in.