Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ type Props = {
* @description Initial value, pass the actual description to initialize the editor
*/
initialValue: string | undefined;
/**
* @description Key, to ensure the editor is re-rendered when the key changes
*/
key: string;
Comment on lines +63 to +66
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Read the file to see the context around lines 63-66
head -n 100 apps/web/core/components/editor/rich-text/description-input/root.tsx | tail -n 50

Repository: makeplane/plane

Length of output: 1831


🏁 Script executed:

# Also get more context by reading the full file structure
wc -l apps/web/core/components/editor/rich-text/description-input/root.tsx

Repository: makeplane/plane

Length of output: 131


🏁 Script executed:

# Let's search for how this component is used elsewhere
rg "DescriptionInput" --type ts --type tsx -A 2 -B 2 | head -n 50

Repository: makeplane/plane

Length of output: 86


🏁 Script executed:

# Search for usages of this component
rg "DescriptionInput" --type ts -A 2 -B 2 | head -n 80

Repository: makeplane/plane

Length of output: 5743


🏁 Script executed:

# Read the actual component implementation to see if key is used
cat -n apps/web/core/components/editor/rich-text/description-input/root.tsx | head -n 150

Repository: makeplane/plane

Length of output: 5965


🏁 Script executed:

# Continue reading the component to see how props are destructured
cat -n apps/web/core/components/editor/rich-text/description-input/root.tsx | sed -n '100,200p'

Repository: makeplane/plane

Length of output: 3879


🏁 Script executed:

# Check the actual call sites to see if they pass a `key` prop
rg "DescriptionInput" -B 3 -A 10 apps/web/core/components/issues/issue-detail/main-content.tsx

Repository: makeplane/plane

Length of output: 1374


🌐 Web query:

React key prop special handling component props

💡 Result:

In React, key is special-cased by React: it’s used internally to identify elements during reconciliation, and it is not forwarded to your component as a normal prop—so props.key is undefined. If you need that same value inside the child, pass it again under a different name. [1]

// ✅ key used by React (not readable in child)
items.map(item => (
  <Row key={item.id} rowId={item.id} />
));

// Row can read rowId, but NOT props.key
function Row({ rowId }) { /* ... */ }

Related: historically ref was also special and not forwarded; starting in React 19, ref can be read as a prop in function components (but not for class components). [1][2]

Sources: React “Special Props Warning” docs [1], React 19 announcement (“ref as a prop”) [2].


Remove key from the Props interface (React reserves it and doesn't pass it to components).

key is a special React attribute handled by the reconciler for element identity and is not passed to component props. The component already demonstrates this by not destructuring key (lines 102–117) despite including it in the type. Including it in the Props interface is misleading—callers may think they're controlling re-renders through a prop when React's JSX key attribute (already used correctly at call sites like key={issue.id}) is what actually drives reconciliation.

🔧 Proposed fix
-  /**
-   * `@description` Key, to ensure the editor is re-rendered when the key changes
-   */
-  key: string;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/**
* @description Key, to ensure the editor is re-rendered when the key changes
*/
key: string;
🤖 Prompt for AI Agents
In `@apps/web/core/components/editor/rich-text/description-input/root.tsx` around
lines 63 - 66, Remove the reserved React "key" property from the Props interface
(the interface named Props in this component) so it is no longer declared as a
prop; update the component's props type accordingly (leave the component's
parameter/destructuring as-is since it already doesn't use key) and ensure
callers continue to use the JSX key attribute (e.g., key={...}) for
reconciliation rather than expecting a "key" prop to be passed.

/**
Comment on lines +64 to 67
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

key is a React-reserved attribute and is not delivered to the component via props, so documenting/typing it as a normal required prop is misleading and can cause unnecessary breaking-type changes. Consider removing key from Props (call sites can still pass the JSX key attribute), or rename this to a real prop (e.g., remountKey) and use it internally to set key on the element that should remount.

Suggested change
* @description Key, to ensure the editor is re-rendered when the key changes
*/
key: string;
/**

Copilot uses AI. Check for mistakes.
* @description Submit handler, the actual function which will be called when the form is submitted
*/
Expand Down
1 change: 1 addition & 0 deletions apps/web/core/components/inbox/content/issue-root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ export const InboxIssueMainContent = observer(function InboxIssueMainContent(pro
entityId={issue.id}
fileAssetType={EFileAssetType.ISSUE_DESCRIPTION}
initialValue={issue.description_html ?? "<p></p>"}
key={issue.id}
onSubmit={async (value, isMigrationUpdate) => {
if (!issue.id || !issue.project_id) return;
await issueOperations.update(workspaceSlug, issue.project_id, issue.id, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ export const IssueMainContent = observer(function IssueMainContent(props: Props)
entityId={issue.id}
fileAssetType={EFileAssetType.ISSUE_DESCRIPTION}
initialValue={issue.description_html}
key={issue.id}
onSubmit={async (value, isMigrationUpdate) => {
if (!issue.id || !issue.project_id) return;
await issueOperations.update(workspaceSlug, issue.project_id, issue.id, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ export const PeekOverviewIssueDetails = observer(function PeekOverviewIssueDetai
entityId={issue.id}
fileAssetType={EFileAssetType.ISSUE_DESCRIPTION}
initialValue={issueDescription}
key={issue.id}
onSubmit={async (value, isMigrationUpdate) => {
if (!issue.id || !issue.project_id) return;
await issueOperations.update(workspaceSlug, issue.project_id, issue.id, {
Expand Down
Loading