[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M754YV563DQEFNWQC17CN9Q5":3,"skill-same:01M754YV563DQEFNWQC17CN9Q5":49},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":19,"linkOnly":20,"markdownContent":21,"markdownBody":22,"frontMatter":23,"refName":27,"commitSha":28,"skillDirectory":29,"forksCount":30,"repositoryHtmlUrl":31,"repositoryHomepageUrl":6,"ownerHtmlUrl":32,"ownerBlogUrl":33,"ownerDescription":6,"updatedAt":34,"install":35,"resources":48},"01M754YV563DQEFNWQC17CN9Q5","recursica-skill-loader",null,"Rules for the Recursica loader, a spinner — when a wait needs a loader, sizes, the text that must go with the loader, and announcing the start and end of a wait. Use for loading states, regions still loading, and actions still running. Not for the result of the wait — see recursica-skill-toast.","borderux\u002Frecursica-knowledge","borderux","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F14911137?v=4","01M754SG94XX2Y7176KM2WGZG3","Border LLC","01M754SGA9E7YSNK6NWVMKMHYC",1,"MIT","https:\u002F\u002Fgithub.com\u002Fborderux\u002Frecursica-knowledge\u002Fblob\u002Fmain\u002Fskills\u002Fcomponents\u002Frecursica-skill-loader\u002FSKILL.md",[],[],"2026-11-12 13:55:43",false,"---\nname: recursica-skill-loader\ndescription: Rules for the Recursica loader, a spinner — when a wait needs a loader, sizes, the text that must go with the loader, and announcing the start and end of a wait. Use for loading states, regions still loading, and actions still running. Not for the result of the wait — see recursica-skill-toast.\nlicense: MIT\nmetadata:\n  author: hi@borderux.com\n  version: 0.2.0\n---\n\n# Loader\n\nA loader shows that work is still in progress. A loader cannot show how much of the work is done, or how much time is left.\n\n## When to use a loader\n\n- The persona waits for an operation of unknown length, such as loading data or a recalculation. A submit action shows the wait in the submit button instead. See `recursica-skill-button`.\n- One region of a page is still loading, and every other region of the page has loaded. The most common example is a dashboard whose widgets load at different speeds. A spinner is most useful in this case:\n\n  - Show the content that has arrived.\n  - Put a spinner in each region that is still loading.\n  - Do not hide the whole page until every region loads.\n\n- The wait is long enough for the persona to notice. If the operation will take more than about 3 seconds, show a loading indicator. `recursica-skill-feedback-messaging` sets the 3-second threshold. A spinner for a shorter wait flashes on and off and looks like a glitch.\n- One region is loading, such as a card, a panel, or a modal. The loader can cover only that region, not the whole screen.\n\n## When not to use a loader\n\n| Situation                                              | Use instead                                                                                                                                                                                                                                                                                                                                                          |\n| ------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| The amount of work or the percentage done is known     | If the theme (the design a designer sets in Theme Forge: the token values, the components, and each component's variants, states and sizes) has a determinate variant (one that shows how much is done), use the determinate variant. Otherwise, show nothing in place of the loader. Report that the screen needs a progress indicator, and see the open questions. |\n| The operation finishes in under about 3 seconds        | Show no loading indicator. A spinner that flashes on and off distracts the persona more than the wait does.                                                                                                                                                                                                                                                          |\n| The wait is over, and the screen must state the result | Text in the place where the result appears, or a toast for a global result. See `recursica-skill-toast`.                                                                                                                                                                                                                                                             |\n| No data exists, and no data ever existed               | An empty state with content in the empty state, never a blank area. A dashboard never shows an empty state. See `recursica-skill-dashboards`.                                                                                                                                                                                                                        |\n| A skeleton screen shown before the content             | **Nothing. Skeleton screens and ghost text are forbidden outright.** See \"Variants\" below.                                                                                                                                                                                                                                                                           |\n| The operation failed                                   | An error message. Stop the spinner and say what happened.                                                                                                                                                                                                                                                                                                            |\n\n**A loader is not an empty state, and not an error state.** A spinner that keeps turning after a request failed tells the persona the app is still trying. In fact, the app has stopped trying.\n\n## Variants\n\n**Use only the loader variants and options that the knowledge MCP server lists for the theme.** A designer can add variants and options in Theme Forge, so each theme can differ. Get the list with the server's `component_api` tool, and use the names the code uses. Never invent a variant, an option, a type, or a state.\n\nEach option below is described by role, such as \"the largest size\". The names in the standard UI kit (the unchanged UI kit in the official Recursica release) are examples only.\n\n- **In the standard UI kit, a loader is an indeterminate spinner.** An indeterminate spinner shows that work is happening, but not how much of the work is done. The indeterminate spinner is the most important fact about the loader.\n- **In the standard UI kit, a loader has three sizes: `small`, `default`, and `large`.** Use the size names from the UI kit (the token file, `recursica_ui-kit.json`, that says which variants and states each component has). The code also uses the UI kit's size names. Each of the two adapters (the Recursica component library for one framework, such as Mantine or Angular Material) also accepts `sm`, `md`, and `lg` for the three sizes. `sm`, `md`, and `lg` work today, but the design system is specified in the UI kit's names. Only the design-system website shows sizes named xs, sm, and md.\n- **If the theme has a determinate variant, use the determinate variant to show progress.** Without a determinate variant, a loader cannot show how far along the work is. Do not show progress in any other form, such as \"45%\". Report that the screen needs a progress indicator, and see the open questions.\n- **Do not show an estimated time left, such as \"About 2 minutes left\".** A spinner cannot show how long the work will take.\n- **If the theme has a slot for a label or text, put the loader's text in the theme's label slot.** Otherwise, place the text as a separate element.\n- **If the theme gives the loader a shimmer, progress bar or type variant, use that loader variant.** The variant is part of the loader, not a separate progress component.\n- **Never use a skeleton screen, even when the theme lists a skeleton screen.** Skeleton screens are forbidden outright. A skeleton screen shows gray placeholder shapes where content will appear. A skeleton screen is also called a skeleton loader or ghost elements. A skeleton screen is a loading indicator, like a spinner. The persona has to work out what the gray shapes are. The gray shapes tell the persona nothing about the content. `recursica-skill-layouts-and-templates` sets the rule: a loading page shows nothing until the page shows content.\n- **Both adapters offer three loader types: Oval, Bars, and Dots.** All three types are available.\n\n  - Use Oval, the default type in both adapters, unless a reason calls for a different type.\n  - Do not use the type to signal any meaning.\n  - Get the name of the type setting in code from the knowledge MCP server.\n\n  Each adapter has a type setting for the three types. Each adapter styles each type, not the UI kit, so a type may look different in each adapter.\n\n- **Only the design-system website shows a track for total progress and an indicator for the percentage done.** See the open questions.\n\n## Rules\n\n**Always show text with the loader, and make the text say what is happening.** Write \"Loading invoices\", not \"Loading\". If the theme has no label slot, place the text beside the loader or below the loader. The text tells the persona what the wait is for. The spinner only shows that a wait is underway.\n\n**Show the loader only over the region that is loading.** Do not cover the whole screen while one card loads. Use a loader across the whole screen only for a wait that affects the whole screen.\n\n**Do not show a loader for a wait under about 3 seconds.** Delay the loader, or leave the loader out. A spinner that appears and disappears at once distracts the persona. The spinner also makes a fast operation feel slower than the operation was. `recursica-skill-feedback-messaging` sets the 3-second threshold.\n\n**Never let the spinning motion be the only signal.** `recursica-skill-design-system-conventions` forbids showing meaning in a single channel (color, shape, position or text, each a separate signal). The persona loses the animation more easily than any other channel:\n\n- A screen reader cannot report the animation.\n- The animation disappears when motion is reduced.\n- A screenshot cannot show the animation.\n\nThe text with the loader is the second channel.\n\n**Follow the operating system's reduced-motion setting** (a setting that asks for less animation). When motion is reduced or removed, two signals must still tell the persona about the wait without the animation:\n\n- the text with the loader\n- the screen reader announcement\n\n**Keep the space the content will fill.** For example, a loading table keeps the height the rows will take. A loader smaller than the content makes the layout jump when the content arrives. The persona then loses the reading position in the text.\n\n**Show one loader per loading region.** Do not nest loaders or stack loaders. Do not show a loader for a region inside a loader for the page.\n\n**Do not leave a control usable behind a loader.** While a submit action is running, the control that started the submit action must not accept a second click. For example, a Save button that started saving a form must not accept a second click.\n\n**Do not use a spinner to suggest that the data updates live.** When a dashboard's components refresh on different schedules, `recursica-skill-dashboards` requires text that says how up to date each component's data is. An example is \"Updated 5 minutes ago\".\n\n## Accessibility\n\nThe rules below add to the accessibility baseline in `recursica-skill-design-system-conventions`, including the focus ring, which every Recursica component follows.\n\nA spinner is only animation. A persona using a screen reader knows a spinner is showing only when the app announces the spinner. The most common failure is a wait that starts and ends with no announcement. The persona then never learns that a wait started or ended. A control the keyboard cannot reach is a less common failure.\n\n### Screen readers\n\n- **Announce that loading has started, and announce that the content has arrived.** Both announcements are required. Apps most often skip the announcement that the content has arrived. When a spinner appears and disappears with no announcement, the persona never learns there was a wait or a result.\n- **Say what is loading, and what arrived.** Announce \"Loading invoices\", then \"24 invoices loaded\". Do not announce only \"Loading\" or \"Loader\".\n- **Announce the start and the end of loading politely, never assertively.** A polite announcement waits for a pause instead of interrupting. The announcement must not interrupt what the persona is reading or typing. The persona does not need to know at once that a wait started or finished. See `recursica-skill-live-regions`.\n- **Put the live region (an area of the page that a screen reader announces automatically when the area's content changes) on the page before the loader appears.** The live region makes the announcement. A screen reader often never announces a live region added at the same moment as the live region's message.\n- **Never announce progress that is not known.** Without a determinate variant, the app has no percentage, no step count, and no time estimate to report. Do not make up a percentage, a step count, or a time estimate.\n- **The spinning motion tells assistive technology nothing.** The motion is a single visual channel. `recursica-skill-design-system-conventions` requires a second channel, which for a loader is the text and the announcement.\n- **Do not announce every check, retry, or refresh.** A region that reloads on a schedule must not announce each reload. Announce only the changes the persona needs to know about.\n- **If a load fails, announce the failure.** When a spinner disappears with no message, the persona assumes the load succeeded. `recursica-skill-live-regions` sets the priority of a failure announcement.\n\n### Keyboard and non-mouse navigation\n\n- **Never put focus on a loader.** A loader is not a control. Give the loader no `tabindex`, no click action, and no code that moves focus to the loader. When an element with focus disappears, the persona's place on the page is lost.\n- **Never leave focus on a control that has disappeared behind the loader.** Before the control is removed or covered, move focus to an element that stays on the page. Otherwise, focus falls to the page body, and the persona's place on the page is lost entirely.\n- **When a region's content is replaced, keep the persona's place.** If focus was inside the region when the content arrives, move focus to the region's heading or first interactive element. Never move focus to the top of the page.\n- **Do not trap the keyboard behind a loader.** The following content must not stay behind the spinner as tab stops (places the Tab key lands) the persona can neither see nor hear:\n\n  - content under the loader\n  - content that has not arrived yet\n\n- **Never show content the persona needs only on hover.** Above all, the text that says what is loading must stay visible.\n\n## Styling set by tokens\n\n**Never set or override the loader's styling.** The theme sets every visual property of the loader, such as size, spacing, borders, colors and animation. Do not add extra containers or spacers to change the loader's look. If the design needs a look the theme does not give, report the missing look as a design-system gap. See `recursica-skill-design-router`.\n\n**Never change the spinner's animation.** The theme sets the spinner's animation.\n\n## Related skills\n\n- `recursica-skill-design-system-conventions` — never showing meaning in a single channel, and one behavioral mode per application.\n- `recursica-skill-dashboards` — the ban on shipping an empty dashboard. The dashboards skill covers text on how up to date each component's data is, for components on different refresh schedules.\n- `recursica-skill-tables` — a loading table shows the loader by default. The tables skill lists error states for a table, including partial failure, as a topic no skill owns.\n- `recursica-skill-buttons-links` — the button that starts any action shows the loading state while the action runs.\n- `recursica-skill-live-regions` — announcing that loading started and finished, and what the app must cover beyond the loader's own announcement.\n\n### Only if used on the same screen\n\n- `recursica-skill-toast` — stating the result once the wait is over.\n\n## Open questions\n\n- **Showing progress.** The user decides how a wait of known length shows progress. Do not assemble a progress indicator from other parts. Do not name a separate progress component as if the theme had a progress component. If progress must be shown, confirm with the user instead of building a progress indicator. Confirm with the user only when the theme has no determinate variant.\n- **Whether the loader may have a label.** Without a label slot, the app places the text beside the loader. No rule says where the text goes relative to the spinner. Confirm with the user only when the theme has no label slot.\n- **Whether the three adapter loader types may be used.** Oval, Bars, and Dots are the three values of a type setting in both adapters. The question covers how each type looks and when to use each type. Only the design-system website shows a progress track. Confirm with the user before relying on a type other than the default. Confirm with the user only when the theme has no type variant.\n- **When a spinner for the whole page is called for, instead of an empty page.** The threshold for showing a loader is about three seconds. The clearest case for a spinner is one region still loading on a page that has otherwise loaded. No rule says where a region ends and the whole page begins.\n- **Loading and error states for a table**, including partial failure. `recursica-skill-tables` settles the loading state: a loading table shows the loader by default. `recursica-skill-tables` lists error states for a table as a topic no skill owns.\n- **Whether the loader itself is delayed.** The 3-second threshold decides whether a wait needs a loader at all. No rule says whether the spinner also waits 3 seconds before appearing. No rule says whether the spinner appears at once for an operation expected to take longer.\n- **Which size to use in which region that holds content.** A page, a panel, and a modal are each a region that holds content. No rule says whether a wait across the whole screen uses the largest size, or a different choice entirely. The largest size is `large` in the standard UI kit.\n\n## Pre-flight checklist\n\n- [ ] The persona waits for an operation of unknown length that takes longer than about 3 seconds. No shorter wait shows a loader.\n- [ ] The loader covers only the region that is loading, and the region has only one loader.\n- [ ] Text beside the loader says what is happening, and names what is loading.\n- [ ] The app claims no time estimate. The app claims no progress or percentage, unless the theme's determinate variant shows the progress.\n- [ ] The spinning motion is not the only signal, and the screen respects the reduced-motion setting.\n- [ ] The loader keeps the space the content will fill, so the layout does not jump when the content arrives.\n- [ ] The start and the end of loading are both announced politely. The announcements come from a live region that was on the page before the loader appeared.\n- [ ] A failure stops the spinner and is announced as a failure, not left silent.\n- [ ] Checks and retries are not announced on every cycle.\n- [ ] Focus is never put on the loader, and never left on a control that disappeared behind the loader.\n- [ ] After a region's content is replaced, focus lands in the new content, not at the top of the page.\n- [ ] Content under the loader, and content that has not arrived, is not left as hidden tab stops.\n- [ ] The text that says what is loading does not appear only on hover.\n- [ ] The focus ring on the controls around the loader is intact.\n- [ ] Every loader size is one the theme's UI kit lists, such as `small`, `default`, or `large` in the standard UI kit. No type, label, track, skeleton screen, or determinate variant is invented.\n- [ ] No styling is set or overridden on the loader. No container or spacer is added to change the loader's look.\n- [ ] The spinner's animation is not changed.\n- [ ] Open questions were asked about, not decided: showing progress, a label on the loader, the three adapter loader types, a spinner for the whole page, loading and error states for a table, delaying the loader, and which size to use in which region that holds content.\n","# Loader\n\nA loader shows that work is still in progress. A loader cannot show how much of the work is done, or how much time is left.\n\n## When to use a loader\n\n- The persona waits for an operation of unknown length, such as loading data or a recalculation. A submit action shows the wait in the submit button instead. See `recursica-skill-button`.\n- One region of a page is still loading, and every other region of the page has loaded. The most common example is a dashboard whose widgets load at different speeds. A spinner is most useful in this case:\n\n  - Show the content that has arrived.\n  - Put a spinner in each region that is still loading.\n  - Do not hide the whole page until every region loads.\n\n- The wait is long enough for the persona to notice. If the operation will take more than about 3 seconds, show a loading indicator. `recursica-skill-feedback-messaging` sets the 3-second threshold. A spinner for a shorter wait flashes on and off and looks like a glitch.\n- One region is loading, such as a card, a panel, or a modal. The loader can cover only that region, not the whole screen.\n\n## When not to use a loader\n\n| Situation                                              | Use instead                                                                                                                                                                                                                                                                                                                                                          |\n| ------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| The amount of work or the percentage done is known     | If the theme (the design a designer sets in Theme Forge: the token values, the components, and each component's variants, states and sizes) has a determinate variant (one that shows how much is done), use the determinate variant. Otherwise, show nothing in place of the loader. Report that the screen needs a progress indicator, and see the open questions. |\n| The operation finishes in under about 3 seconds        | Show no loading indicator. A spinner that flashes on and off distracts the persona more than the wait does.                                                                                                                                                                                                                                                          |\n| The wait is over, and the screen must state the result | Text in the place where the result appears, or a toast for a global result. See `recursica-skill-toast`.                                                                                                                                                                                                                                                             |\n| No data exists, and no data ever existed               | An empty state with content in the empty state, never a blank area. A dashboard never shows an empty state. See `recursica-skill-dashboards`.                                                                                                                                                                                                                        |\n| A skeleton screen shown before the content             | **Nothing. Skeleton screens and ghost text are forbidden outright.** See \"Variants\" below.                                                                                                                                                                                                                                                                           |\n| The operation failed                                   | An error message. Stop the spinner and say what happened.                                                                                                                                                                                                                                                                                                            |\n\n**A loader is not an empty state, and not an error state.** A spinner that keeps turning after a request failed tells the persona the app is still trying. In fact, the app has stopped trying.\n\n## Variants\n\n**Use only the loader variants and options that the knowledge MCP server lists for the theme.** A designer can add variants and options in Theme Forge, so each theme can differ. Get the list with the server's `component_api` tool, and use the names the code uses. Never invent a variant, an option, a type, or a state.\n\nEach option below is described by role, such as \"the largest size\". The names in the standard UI kit (the unchanged UI kit in the official Recursica release) are examples only.\n\n- **In the standard UI kit, a loader is an indeterminate spinner.** An indeterminate spinner shows that work is happening, but not how much of the work is done. The indeterminate spinner is the most important fact about the loader.\n- **In the standard UI kit, a loader has three sizes: `small`, `default`, and `large`.** Use the size names from the UI kit (the token file, `recursica_ui-kit.json`, that says which variants and states each component has). The code also uses the UI kit's size names. Each of the two adapters (the Recursica component library for one framework, such as Mantine or Angular Material) also accepts `sm`, `md`, and `lg` for the three sizes. `sm`, `md`, and `lg` work today, but the design system is specified in the UI kit's names. Only the design-system website shows sizes named xs, sm, and md.\n- **If the theme has a determinate variant, use the determinate variant to show progress.** Without a determinate variant, a loader cannot show how far along the work is. Do not show progress in any other form, such as \"45%\". Report that the screen needs a progress indicator, and see the open questions.\n- **Do not show an estimated time left, such as \"About 2 minutes left\".** A spinner cannot show how long the work will take.\n- **If the theme has a slot for a label or text, put the loader's text in the theme's label slot.** Otherwise, place the text as a separate element.\n- **If the theme gives the loader a shimmer, progress bar or type variant, use that loader variant.** The variant is part of the loader, not a separate progress component.\n- **Never use a skeleton screen, even when the theme lists a skeleton screen.** Skeleton screens are forbidden outright. A skeleton screen shows gray placeholder shapes where content will appear. A skeleton screen is also called a skeleton loader or ghost elements. A skeleton screen is a loading indicator, like a spinner. The persona has to work out what the gray shapes are. The gray shapes tell the persona nothing about the content. `recursica-skill-layouts-and-templates` sets the rule: a loading page shows nothing until the page shows content.\n- **Both adapters offer three loader types: Oval, Bars, and Dots.** All three types are available.\n\n  - Use Oval, the default type in both adapters, unless a reason calls for a different type.\n  - Do not use the type to signal any meaning.\n  - Get the name of the type setting in code from the knowledge MCP server.\n\n  Each adapter has a type setting for the three types. Each adapter styles each type, not the UI kit, so a type may look different in each adapter.\n\n- **Only the design-system website shows a track for total progress and an indicator for the percentage done.** See the open questions.\n\n## Rules\n\n**Always show text with the loader, and make the text say what is happening.** Write \"Loading invoices\", not \"Loading\". If the theme has no label slot, place the text beside the loader or below the loader. The text tells the persona what the wait is for. The spinner only shows that a wait is underway.\n\n**Show the loader only over the region that is loading.** Do not cover the whole screen while one card loads. Use a loader across the whole screen only for a wait that affects the whole screen.\n\n**Do not show a loader for a wait under about 3 seconds.** Delay the loader, or leave the loader out. A spinner that appears and disappears at once distracts the persona. The spinner also makes a fast operation feel slower than the operation was. `recursica-skill-feedback-messaging` sets the 3-second threshold.\n\n**Never let the spinning motion be the only signal.** `recursica-skill-design-system-conventions` forbids showing meaning in a single channel (color, shape, position or text, each a separate signal). The persona loses the animation more easily than any other channel:\n\n- A screen reader cannot report the animation.\n- The animation disappears when motion is reduced.\n- A screenshot cannot show the animation.\n\nThe text with the loader is the second channel.\n\n**Follow the operating system's reduced-motion setting** (a setting that asks for less animation). When motion is reduced or removed, two signals must still tell the persona about the wait without the animation:\n\n- the text with the loader\n- the screen reader announcement\n\n**Keep the space the content will fill.** For example, a loading table keeps the height the rows will take. A loader smaller than the content makes the layout jump when the content arrives. The persona then loses the reading position in the text.\n\n**Show one loader per loading region.** Do not nest loaders or stack loaders. Do not show a loader for a region inside a loader for the page.\n\n**Do not leave a control usable behind a loader.** While a submit action is running, the control that started the submit action must not accept a second click. For example, a Save button that started saving a form must not accept a second click.\n\n**Do not use a spinner to suggest that the data updates live.** When a dashboard's components refresh on different schedules, `recursica-skill-dashboards` requires text that says how up to date each component's data is. An example is \"Updated 5 minutes ago\".\n\n## Accessibility\n\nThe rules below add to the accessibility baseline in `recursica-skill-design-system-conventions`, including the focus ring, which every Recursica component follows.\n\nA spinner is only animation. A persona using a screen reader knows a spinner is showing only when the app announces the spinner. The most common failure is a wait that starts and ends with no announcement. The persona then never learns that a wait started or ended. A control the keyboard cannot reach is a less common failure.\n\n### Screen readers\n\n- **Announce that loading has started, and announce that the content has arrived.** Both announcements are required. Apps most often skip the announcement that the content has arrived. When a spinner appears and disappears with no announcement, the persona never learns there was a wait or a result.\n- **Say what is loading, and what arrived.** Announce \"Loading invoices\", then \"24 invoices loaded\". Do not announce only \"Loading\" or \"Loader\".\n- **Announce the start and the end of loading politely, never assertively.** A polite announcement waits for a pause instead of interrupting. The announcement must not interrupt what the persona is reading or typing. The persona does not need to know at once that a wait started or finished. See `recursica-skill-live-regions`.\n- **Put the live region (an area of the page that a screen reader announces automatically when the area's content changes) on the page before the loader appears.** The live region makes the announcement. A screen reader often never announces a live region added at the same moment as the live region's message.\n- **Never announce progress that is not known.** Without a determinate variant, the app has no percentage, no step count, and no time estimate to report. Do not make up a percentage, a step count, or a time estimate.\n- **The spinning motion tells assistive technology nothing.** The motion is a single visual channel. `recursica-skill-design-system-conventions` requires a second channel, which for a loader is the text and the announcement.\n- **Do not announce every check, retry, or refresh.** A region that reloads on a schedule must not announce each reload. Announce only the changes the persona needs to know about.\n- **If a load fails, announce the failure.** When a spinner disappears with no message, the persona assumes the load succeeded. `recursica-skill-live-regions` sets the priority of a failure announcement.\n\n### Keyboard and non-mouse navigation\n\n- **Never put focus on a loader.** A loader is not a control. Give the loader no `tabindex`, no click action, and no code that moves focus to the loader. When an element with focus disappears, the persona's place on the page is lost.\n- **Never leave focus on a control that has disappeared behind the loader.** Before the control is removed or covered, move focus to an element that stays on the page. Otherwise, focus falls to the page body, and the persona's place on the page is lost entirely.\n- **When a region's content is replaced, keep the persona's place.** If focus was inside the region when the content arrives, move focus to the region's heading or first interactive element. Never move focus to the top of the page.\n- **Do not trap the keyboard behind a loader.** The following content must not stay behind the spinner as tab stops (places the Tab key lands) the persona can neither see nor hear:\n\n  - content under the loader\n  - content that has not arrived yet\n\n- **Never show content the persona needs only on hover.** Above all, the text that says what is loading must stay visible.\n\n## Styling set by tokens\n\n**Never set or override the loader's styling.** The theme sets every visual property of the loader, such as size, spacing, borders, colors and animation. Do not add extra containers or spacers to change the loader's look. If the design needs a look the theme does not give, report the missing look as a design-system gap. See `recursica-skill-design-router`.\n\n**Never change the spinner's animation.** The theme sets the spinner's animation.\n\n## Related skills\n\n- `recursica-skill-design-system-conventions` — never showing meaning in a single channel, and one behavioral mode per application.\n- `recursica-skill-dashboards` — the ban on shipping an empty dashboard. The dashboards skill covers text on how up to date each component's data is, for components on different refresh schedules.\n- `recursica-skill-tables` — a loading table shows the loader by default. The tables skill lists error states for a table, including partial failure, as a topic no skill owns.\n- `recursica-skill-buttons-links` — the button that starts any action shows the loading state while the action runs.\n- `recursica-skill-live-regions` — announcing that loading started and finished, and what the app must cover beyond the loader's own announcement.\n\n### Only if used on the same screen\n\n- `recursica-skill-toast` — stating the result once the wait is over.\n\n## Open questions\n\n- **Showing progress.** The user decides how a wait of known length shows progress. Do not assemble a progress indicator from other parts. Do not name a separate progress component as if the theme had a progress component. If progress must be shown, confirm with the user instead of building a progress indicator. Confirm with the user only when the theme has no determinate variant.\n- **Whether the loader may have a label.** Without a label slot, the app places the text beside the loader. No rule says where the text goes relative to the spinner. Confirm with the user only when the theme has no label slot.\n- **Whether the three adapter loader types may be used.** Oval, Bars, and Dots are the three values of a type setting in both adapters. The question covers how each type looks and when to use each type. Only the design-system website shows a progress track. Confirm with the user before relying on a type other than the default. Confirm with the user only when the theme has no type variant.\n- **When a spinner for the whole page is called for, instead of an empty page.** The threshold for showing a loader is about three seconds. The clearest case for a spinner is one region still loading on a page that has otherwise loaded. No rule says where a region ends and the whole page begins.\n- **Loading and error states for a table**, including partial failure. `recursica-skill-tables` settles the loading state: a loading table shows the loader by default. `recursica-skill-tables` lists error states for a table as a topic no skill owns.\n- **Whether the loader itself is delayed.** The 3-second threshold decides whether a wait needs a loader at all. No rule says whether the spinner also waits 3 seconds before appearing. No rule says whether the spinner appears at once for an operation expected to take longer.\n- **Which size to use in which region that holds content.** A page, a panel, and a modal are each a region that holds content. No rule says whether a wait across the whole screen uses the largest size, or a different choice entirely. The largest size is `large` in the standard UI kit.\n\n## Pre-flight checklist\n\n- [ ] The persona waits for an operation of unknown length that takes longer than about 3 seconds. No shorter wait shows a loader.\n- [ ] The loader covers only the region that is loading, and the region has only one loader.\n- [ ] Text beside the loader says what is happening, and names what is loading.\n- [ ] The app claims no time estimate. The app claims no progress or percentage, unless the theme's determinate variant shows the progress.\n- [ ] The spinning motion is not the only signal, and the screen respects the reduced-motion setting.\n- [ ] The loader keeps the space the content will fill, so the layout does not jump when the content arrives.\n- [ ] The start and the end of loading are both announced politely. The announcements come from a live region that was on the page before the loader appeared.\n- [ ] A failure stops the spinner and is announced as a failure, not left silent.\n- [ ] Checks and retries are not announced on every cycle.\n- [ ] Focus is never put on the loader, and never left on a control that disappeared behind the loader.\n- [ ] After a region's content is replaced, focus lands in the new content, not at the top of the page.\n- [ ] Content under the loader, and content that has not arrived, is not left as hidden tab stops.\n- [ ] The text that says what is loading does not appear only on hover.\n- [ ] The focus ring on the controls around the loader is intact.\n- [ ] Every loader size is one the theme's UI kit lists, such as `small`, `default`, or `large` in the standard UI kit. No type, label, track, skeleton screen, or determinate variant is invented.\n- [ ] No styling is set or overridden on the loader. No container or spacer is added to change the loader's look.\n- [ ] The spinner's animation is not changed.\n- [ ] Open questions were asked about, not decided: showing progress, a label on the loader, the three adapter loader types, a spinner for the whole page, loading and error states for a table, delaying the loader, and which size to use in which region that holds content.\n",{"name":5,"license":15,"metadata":24,"description":7},{"author":25,"version":26},"hi@borderux.com","0.2.0","main","110b382bfe525d171ba33c7074d6ad1f3762548f","skills\u002Fcomponents\u002Frecursica-skill-loader",0,"https:\u002F\u002Fgithub.com\u002Fborderux\u002Frecursica-knowledge","https:\u002F\u002Fgithub.com\u002Fborderux","https:\u002F\u002Fborderux.com","2026-11-09 16:39:27",{"source":8,"skillName":5,"commands":36,"prompt":46,"zipAvailable":47},[37,40,43],{"tool":38,"command":39},"npx","npx skills add borderux\u002Frecursica-knowledge --skill recursica-skill-loader",{"tool":41,"command":42},"bunx","bunx skills add borderux\u002Frecursica-knowledge --skill recursica-skill-loader",{"tool":44,"command":45},"pnpm","pnpm dlx skills add borderux\u002Frecursica-knowledge --skill recursica-skill-loader","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fborderux\u002Frecursica-knowledge\u002Fblob\u002Fmain\u002Fskills\u002Fcomponents\u002Frecursica-skill-loader\u002FSKILL.md",true,[],[50,58,65,72,79,86],{"skillNo":51,"name":52,"nameZh":6,"description":53,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":54,"sourceHtmlUrl":55,"categories":56,"keywords":57,"publishedAt":19},"01M7556E67F3DCE39P7ZTVT5TA","recursica-skill-template","Replace with a description of the skill and its purpose.","https:\u002F\u002Fgithub.com\u002Fborderux\u002Frecursica-knowledge\u002Fblob\u002Fmain\u002Ftemplate\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fborderux\u002Frecursica-knowledge\u002Fblob\u002Fmain\u002Ftemplate\u002FSKILL.md",[],[],{"skillNo":59,"name":60,"nameZh":6,"description":61,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":62,"categories":63,"keywords":64,"publishedAt":19},"01M75569FCJXWWGXRVMTJFBK0W","recursica-skill-working-memory","The research behind Recursica's item-count limits, with citations — Miller's 7 ± 2, Cowan's 4, chunking, and recognition versus recall. Use when a decision turns on how many options, navigation items, or chips to show at once, or to justify or challenge a count. Not for choosing a control — see recursica-skill-selection-controls.","https:\u002F\u002Fgithub.com\u002Fborderux\u002Frecursica-knowledge\u002Fblob\u002Fmain\u002Fskills\u002Fpsychology\u002Frecursica-skill-working-memory\u002FSKILL.md",[],[],{"skillNo":66,"name":67,"nameZh":6,"description":68,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":69,"categories":70,"keywords":71,"publishedAt":19},"01M75564EC5E5QKBPNWARQVDBC","recursica-skill-discoverability","The research behind Recursica's rule that rarely needed settings get a real but unpromoted entry point — the paradox of the active user, satisficing (settling for the first method that is good enough), and progressive disclosure, with citations. Use when deciding whether to hide, promote, or build a configuration or customization feature, or to justify that choice. Not for item counts — see recursica-skill-working-memory.","https:\u002F\u002Fgithub.com\u002Fborderux\u002Frecursica-knowledge\u002Fblob\u002Fmain\u002Fskills\u002Fpsychology\u002Frecursica-skill-discoverability\u002FSKILL.md",[],[],{"skillNo":73,"name":74,"nameZh":6,"description":75,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":76,"categories":77,"keywords":78,"publishedAt":19},"01M7555Z2YRG9YSM01KMYT1FY5","recursica-skill-design-router","Start here for any Recursica screen work. The router says what to decide in what order, which skill owns each decision, which rule wins when two rules conflict, and when to confirm with the user instead of guessing. Load the router first to design, build, review, or refactor a screen, page, panel, or flow, or when rules seem to disagree or no rule applies. The router routes, and the owning skill holds the rules.","https:\u002F\u002Fgithub.com\u002Fborderux\u002Frecursica-knowledge\u002Fblob\u002Fmain\u002Fskills\u002Fmeta\u002Frecursica-skill-design-router\u002FSKILL.md",[],[],{"skillNo":80,"name":81,"nameZh":6,"description":82,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":83,"categories":84,"keywords":85,"publishedAt":19},"01M7555RYHBH6XM48V2420Z66X","recursica-skill-undo","House rules for undo — when an action gets an undo instead of a confirmation, where the undo goes (on the page, in place, or in a toast), when a toast is needed at all, and the Undo button's accessible name. Use whenever an action can be reversed, or when choosing between an undo and a confirmation. Not for building the toast that holds an Undo button — see recursica-skill-toast. Not for the confirmation modal — see recursica-skill-buttons-links.","https:\u002F\u002Fgithub.com\u002Fborderux\u002Frecursica-knowledge\u002Fblob\u002Fmain\u002Fskills\u002Fdesign-rules\u002Frecursica-skill-undo\u002FSKILL.md",[],[],{"skillNo":87,"name":88,"nameZh":6,"description":89,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":90,"categories":91,"keywords":92,"publishedAt":19},"01M7555K4E6TKJ9E9P7GCQYJZ8","recursica-skill-typography-semantics","House rules for type and semantic markup — real elements instead of styled divs, one H1 per page, type styles from tokens only, loading the brand typefaces, hidden headings, emphasis with em and strong, abbreviations, and AP style. Use for headings, body copy, emphasis, and the markup under a visual hierarchy. Not for naming — see recursica-skill-names-and-terms.","https:\u002F\u002Fgithub.com\u002Fborderux\u002Frecursica-knowledge\u002Fblob\u002Fmain\u002Fskills\u002Fdesign-rules\u002Frecursica-skill-typography-semantics\u002FSKILL.md",[],[]]