Instruction file imported from xability/maidr (
.github/instructions/ui.instructions.md). Copyright stays with the author.
View layer
React components in src/ui/ render state. They hold no business logic.
Shape
export const Text: React.FC = () => {
const { enabled, value, announce } = useViewModelState('text');
return (
<div>
{enabled && <p aria-live={announce ? 'assertive' : 'off'}>{value}</p>}
</div>
);
};
Rules
- State comes from
useViewModelState(key). NouseSelector, no service imports, no model imports. A component that reaches past the ViewModel breaks the architecture. - User actions go out through
useViewModel(key)or a dispatched command — never by calling a service method directly. - Functional components only, with typed props. Keep each component to one
responsibility and extract reusable logic into hooks under
src/state/hook/. - Memoize deliberately.
useMemofor expensive derivations,useCallbackfor callbacks passed as props,React.memowhere a component re-renders on stable props. Do not wrap everything by reflex. - Keep
useEffectdependency arrays complete and honest; add cleanup returns for anything that subscribes or schedules. - Never render untrusted data as markup. No
dangerouslySetInnerHTMLand noinnerHTMLwith anything that reaches the page from chart input, an LLM response, or a live data feed. Render it as text and let React escape it. - Register new components in
src/ui/App.tsx.
Accessibility is not optional here
This is an accessibility library — a visually correct component that a screen
reader cannot use is a broken component. Before finishing any component, check
the rules in accessibility.instructions.md: live regions, labels and roles, keyboard
operability, visible focus, and contrast.