-
Notifications
You must be signed in to change notification settings - Fork 13
Open
Labels
Description
Summary
Apsara's dev dependency is already on the latest React, but the codebase still uses legacy patterns. We should fully adopt modern React APIs and drop legacy support.
Current state
- Dev dependency:
react@^19.0.1 - Peer dependency:
react@^18 || ^19(needs updating to^19) - Deprecated
forwardRefusage: 164 occurrences across 63 files —refis now a regular prop and the wrapper is unnecessary displayNameassignments: 60+ components (only needed because of the deprecated wrapper)useImperativeHandle: not used anywhere- Other deprecated APIs: none found — no class components, no string refs, no legacy context, no
react-dom/test-utils
Key changes in modern React
refis a regular prop — the deprecatedforwardRefwrapper is no longer neededdisplayNameauto-inferred — named function declarations don't need explicitdisplayNamerefcleanup functions — ref callbacks can return a cleanup functionuse()hook — read resources (promises, context) during renderuseActionState— manages form action stateuseOptimistic— optimistic UI updates<Context>as provider — no need for<Context.Provider>- Document metadata — native
<title>,<meta>,<link>hoisting - Stylesheet precedence — built-in
<link rel="stylesheet" precedence="..."> - Async script support —
<script async>deduplication
Migration steps
Required
- Update peer dependency from
^18 || ^19to^19inpackages/raystack/package.json - Remove deprecated ref wrapper from all 63 component files — accept
refas a regular prop instead - Remove
displayNameassignments — named function declarations auto-infer the name - Update type patterns — replace
ElementRef<typeof Primitive>with direct HTML element types where possible - Verify third-party compatibility — ensure Base UI, Radix, and cmdk primitives work with ref-as-prop
Optional (adopt new APIs where beneficial)
- Replace
<Context.Provider>with<Context>if used anywhere - Evaluate
use()hook for async data patterns - Update docs/stories referencing old patterns
Validation
- Run full test suite and verify no regressions
- Test with consuming apps to ensure nothing breaks
Migration example
// Before (legacy pattern)
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>((props, ref) => (
<button ref={ref} {...props} />
));
Button.displayName = 'Button';
// After (modern pattern)
function Button({ ref, ...props }: ButtonProps & { ref?: React.Ref<HTMLButtonElement> }) {
return <button ref={ref} {...props} />;
}Affected components (63 files)
Accordion, Amount, Avatar, Breadcrumb, Button, Callout, Checkbox, CodeBlock, Combobox, Command, CopyButton, DataTable, Dialog, DropdownMenu, Flex, Grid, Headline, IconButton, InputField, Link, Navbar, Popover, Radio, ScrollArea, Search, Select, Sheet, Sidebar, Slider, Spinner, Switch, Table, Tabs, Text, TextArea
Breaking change
This is a breaking change — consumers on older React versions will need to upgrade.
Files
packages/raystack/package.json(peer dep)packages/raystack/components/(all 63 component files)
Reactions are currently unavailable