Skip to content

Commit 04a9e16

Browse files
authored
fix(clerk-js): Prevent leak of data-component-status (#6884)
1 parent 453b7ca commit 04a9e16

File tree

4 files changed

+68
-2
lines changed

4 files changed

+68
-2
lines changed

.changeset/rich-peaches-yawn.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@clerk/clerk-js': patch
3+
---
4+
5+
Prevent leaking the `data-component-status` attribute for components other than `<PricingTable/>`.
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { render } from '@testing-library/react';
2+
import { describe, expect, it } from 'vitest';
3+
4+
import { AppearanceProvider } from '../AppearanceContext';
5+
import { Flow } from '../Flow';
6+
7+
describe('Flow.Root data-component-status behavior', () => {
8+
it('does not set data-component-status if prop is omitted', () => {
9+
const { container } = render(
10+
<AppearanceProvider appearanceKey='signIn'>
11+
<Flow.Root flow='signIn'>
12+
<div data-testid='child' />
13+
</Flow.Root>
14+
,
15+
</AppearanceProvider>,
16+
);
17+
18+
const host = container as HTMLElement | null;
19+
expect(host).toBeTruthy();
20+
// Attribute should not be present
21+
expect(host?.getAttribute('data-component-status')).toBeNull();
22+
});
23+
24+
it('sets data-component-status="awaiting-data" when isFlowReady=false', async () => {
25+
const { container } = render(
26+
<AppearanceProvider appearanceKey='signIn'>
27+
<Flow.Root
28+
flow='signIn'
29+
isFlowReady={false}
30+
>
31+
<div data-testid='child' />
32+
</Flow.Root>
33+
,
34+
</AppearanceProvider>,
35+
);
36+
37+
const host = container as HTMLElement | null;
38+
expect(host).toBeTruthy();
39+
expect(host?.getAttribute('data-component-status')).toBe('awaiting-data');
40+
});
41+
42+
it('sets data-component-status="ready" when isFlowReady=true', () => {
43+
const { container } = render(
44+
<AppearanceProvider appearanceKey='signIn'>
45+
<Flow.Root
46+
flow='signIn'
47+
isFlowReady
48+
>
49+
<div data-testid='child' />
50+
</Flow.Root>
51+
,
52+
</AppearanceProvider>,
53+
);
54+
55+
const host = container as HTMLElement | null;
56+
expect(host).toBeTruthy();
57+
expect(host?.getAttribute('data-component-status')).toBe('ready');
58+
});
59+
});

packages/clerk-js/src/ui/elements/InvisibleRootBox.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ const _InvisibleRootBox = React.memo((props: RootBoxProps & { isFlowReady?: bool
1818
}
1919

2020
parent.setAttribute('class', props.className);
21-
parent.setAttribute('data-component-status', props.isFlowReady ? 'ready' : 'awaiting-data');
21+
if ('isFlowReady' in props) {
22+
parent.setAttribute('data-component-status', props.isFlowReady ? 'ready' : 'awaiting-data');
23+
}
2224
}, [props.className, props.isFlowReady]);
2325

2426
return (

packages/clerk-js/src/ui/elements/contexts/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ const [FlowMetadataCtx, useFlowMetadata] = createContextAndHook<FlowMetadata>('F
129129

130130
export const FlowMetadataProvider = (props: React.PropsWithChildren<FlowMetadata>) => {
131131
const { flow, part } = props;
132-
const value = React.useMemo(() => ({ value: { ...props } }), [flow, part]);
132+
const value = React.useMemo(() => ({ value: props }), [flow, part]);
133133
return <FlowMetadataCtx.Provider value={value}>{props.children}</FlowMetadataCtx.Provider>;
134134
};
135135

0 commit comments

Comments
 (0)