From fa8e7826f502eda067a3f80a6079898ecd3069bd Mon Sep 17 00:00:00 2001 From: Oliver Geneser Date: Wed, 2 Sep 2026 10:55:53 +0200 Subject: [PATCH 1/2] fix: ref in functional components --- src/overridable.js | 10 ++++++---- src/overridable.test.js | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/overridable.js b/src/overridable.js index 24be219..19b9a6b 100644 --- a/src/overridable.js +++ b/src/overridable.js @@ -36,7 +36,7 @@ export function parametrize(Component, extraProps) { /** * React component to enable overriding children when rendering. */ -function Overridable({id, children, ...restProps}) { +const Overridable = React.forwardRef(({id, children, ...restProps}, ref) => { const overriddenComponents = useContext(OverridableContext); const child = children ? React.Children.only(children) : null; const childProps = child ? child.props : {}; @@ -44,16 +44,18 @@ function Overridable({id, children, ...restProps}) { if (id in overriddenComponents) { // If there's an override, we replace the component's content with the override + props const Overridden = overriddenComponents[id]; - const element = React.createElement(Overridden, {...childProps, ...restProps}); + const props = {...childProps, ...restProps}; + if (ref) props.ref = ref; + const element = React.createElement(Overridden, props); return {element}; } else if (child) { // No override? Clone the Overridable component's original children - const element = React.cloneElement(child, childProps); + const element = ref ? React.cloneElement(child, {ref}) : React.cloneElement(child, childProps); return {element}; } else { return null; } -} +}); Overridable.propTypes = { /** The children of the component */ diff --git a/src/overridable.test.js b/src/overridable.test.js index b7a1f4b..7be8562 100644 --- a/src/overridable.test.js +++ b/src/overridable.test.js @@ -221,3 +221,42 @@ describe('Tests for Overridable.component', () => { expect(NewCmp.find('ul')).toHaveLength(0); }); }); + +describe('Tests for ref forwarding', () => { + class RefChild extends Component { + render() { + return
; + } + } + + test('it should forward a ref to the cloned child', () => { + const ref = React.createRef(); + mount( + + + + ); + expect(ref.current).toBeInstanceOf(RefChild); + }); + + test('it should forward a ref to the overridden component', () => { + const ref = React.createRef(); + mount( + + +
+ + + ); + expect(ref.current).toBeInstanceOf(RefChild); + }); + + test('it should render normally when no ref is given', () => { + const mounted = mount( + + + + ); + expect(mounted.find('.ref-child')).toHaveLength(1); + }); +}); From 1d484598ad866db4622416d0765ef6acbb5b6ca4 Mon Sep 17 00:00:00 2001 From: Oliver Geneser Date: Wed, 2 Sep 2026 11:04:12 +0200 Subject: [PATCH 2/2] feat: add display name --- src/overridable.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/overridable.js b/src/overridable.js index 19b9a6b..42a4ff6 100644 --- a/src/overridable.js +++ b/src/overridable.js @@ -45,7 +45,9 @@ const Overridable = React.forwardRef(({id, children, ...restProps}, ref) => { // If there's an override, we replace the component's content with the override + props const Overridden = overriddenComponents[id]; const props = {...childProps, ...restProps}; - if (ref) props.ref = ref; + if (ref) { + props.ref = ref; + } const element = React.createElement(Overridden, props); return {element}; } else if (child) { @@ -57,6 +59,8 @@ const Overridable = React.forwardRef(({id, children, ...restProps}, ref) => { } }); +Overridable.displayName = 'Overridable'; + Overridable.propTypes = { /** The children of the component */ children: PropTypes.node,