{
  "id": 5150935,
  "title": "Why Your Loading Spinner Flickers, and the Two Rules That Fix It",
  "url": "https://urgent.news/2026/09/02/why-your-loading-spinner-flickers-and-the-two-rules-that-fix-it",
  "topic": "tech",
  "section": "Tech",
  "published": "2026-09-02T19:07:49.000Z",
  "source": {
    "name": "Dev.to",
    "slug": "dev-to",
    "url": "https://dev.to/devshakib/why-your-loading-spinner-flickers-and-the-two-rules-that-fix-it-2jn6"
  },
  "original_language": "en",
  "account": "Every Flutter application contains a loading spinner, typically represented by a bool variable and a Stack widget. This approach is common, found in tutorials, and correct in principle. However, the implementation often results in a visually unappealing flickering effect on fast networks. This issue arises from the timing of the spinner's appearance and disappearance, not the spinner's design itself.\n\nThe primary cause of flickering is the timing of the API call, which typically takes around 90 milliseconds to complete. At 60 frames per second, this equates to approximately five and a half frames. As a result, the spinner mounts, paints for five frames, and then unmounts. To a user, this appears as a flash of grey, an unnoticeable shape that vanishes before their eye can focus on it. This effect is exacerbated when the timing of the API call is near the boundary of 100 milliseconds. For example, an operation that takes 200ms on Wi-Fi versus 900ms on cellular network connections can produce vastly different user experiences: a flickering screen on the fast network versus a seamless wait on the slow network.\n\nThe underlying principle is that showing progress below a certain threshold (around 100ms) can actually be counterproductive. Jakob Nielsen's research highlights a response-time limit of 0.1 seconds for actions to feel instantaneous, and 1 second for uninterrupted thought flow. Below this threshold, displaying progress can disrupt the user's experience more than not displaying it at all. Therefore, a third state is necessary - an intermediate state that indicates progress without being noticeable.\n\nTo address this issue, two key rules should be followed. Rule one states that nothing should paint before the reveal delay. Upon initiating an operation, a timer should be started. If the operation completes before the timer fires, no visual feedback should be rendered. This threshold is typically around 140 milliseconds. If the operation completes before this threshold, no spinner or other visual feedback is displayed. If it exceeds the threshold, the user begins to question whether their tap was registered, and feedback becomes reassuring. This single rule significantly reduces flickering in most applications, as most requests are fast and can go unnoticed.\n\nRule two is equally crucial but less apparent. When the reveal delay is set to 140ms, and the request finishes at 170ms, the spinner appears for only 30 milliseconds. This replacement of the five-frame flash with a two-frame flash is less desirable. The second rule dictates that once the overlay is committed to appearing, it must remain visible for at least half a second. This ensures the interface appears deliberate rather than glitchy, even if it means waiting slightly longer than strictly necessary.\n\nThese two rules form the foundation of the Loading Kit library, which implements these principles to ensure a smoother user experience. The library automatically handles errors and other aspects of loading states, focusing on the critical role of timing in loading indicators.",
  "summary": "Every Flutter app has this somewhere: bool _loading = false ; Future < void > _signIn () async { setState (() = > _loading = true ); try { await api . signIn ( email , password ); } finally { setState (() = > _loading = false ); } } And a Stack with a spinner on top when _loading is true. It is the first thing everyone writes, it is in every tutorial, and it is correct in the sense that the state…",
  "key_points": [
    "Flickering spinner caused by API call timing, not design",
    "90ms API call equates to ~5.5 frames at 60fps",
    "Flicker worsens near 100ms threshold"
  ],
  "editors_take": null,
  "illustration": null,
  "coverage": {
    "outlets": 1,
    "also_reported_by": []
  },
  "ai_generated": true,
  "disclaimer": "Summaries, key points and the editor’s take are written by software from other outlets’ reporting and may contain errors — always check the linked original."
}