{"id":13481689,"url":"https://github.com/sastan/react-render-callback","last_synced_at":"2025-06-17T01:03:10.450Z","repository":{"id":57343486,"uuid":"147655916","full_name":"sastan/react-render-callback","owner":"sastan","description":"render-prop helper to render anything (Functions, Components, Elements, ...)","archived":false,"fork":false,"pushed_at":"2020-05-31T00:02:34.000Z","size":249,"stargazers_count":9,"open_issues_count":16,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-05-07T14:23:49.119Z","etag":null,"topics":["component-injection","function-as-child","function-as-child-pattern","react","render-props"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sastan.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-09-06T10:14:25.000Z","updated_at":"2021-01-25T18:27:32.000Z","dependencies_parsed_at":"2022-09-12T07:00:29.852Z","dependency_job_id":null,"html_url":"https://github.com/sastan/react-render-callback","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sastan%2Freact-render-callback","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sastan%2Freact-render-callback/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sastan%2Freact-render-callback/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sastan%2Freact-render-callback/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sastan","download_url":"https://codeload.github.com/sastan/react-render-callback/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254509729,"owners_count":22082963,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["component-injection","function-as-child","function-as-child-pattern","react","render-props"],"created_at":"2024-07-31T17:00:54.288Z","updated_at":"2025-06-17T01:03:10.268Z","avatar_url":"https://github.com/sastan.png","language":"JavaScript","funding_links":[],"categories":["Components"],"sub_categories":["Misc"],"readme":"# react-render-callback\n\n\u003e render-prop helper to render anything (Functions, Components, Elements, ...)\n\n[![version][version-badge]][package]\n[![MIT License][license-badge]][license]\n[![module formats: umd, cjs, and es][module-formats-badge]][unpkg-dist]\n[![umd size][size-badge]][unpkg-dist]\n[![umd gzip size][gzip-badge]][unpkg-dist]\n\n[![Build Status][build-badge]][build]\n[![Code Coverage][coverage-badge]][coverage]\n[![Maintainability][maintainability-badge]][maintainability]\n[![PRs Welcome][prs-badge]][prs]\n[![Code of Conduct][coc-badge]][coc]\n\n[![Sponsored by Kenoxa][sponsored-by-badge]][sponsored-by]\n[![Semver][semver-badge]][semver]\n[![semantic-release][semantic-release-badge]][semantic-release]\n[![Greenkeeper badge][greenkeeper-badge]][greenkeeper]\n\n## The problem\n\nYou want your component to support the [`render prop`][render-prop] [pattern][use-a-render-prop]\nwith different types of values like\n[Function as children][function-as-children],\na [React.Component][react-component] (Component Injection)\nor just plain react elements.\n\n## This solution\n\n`react-render-callback` frees you from detecting what kind fo [`render prop`][render-prop]\nyour component is dealing with:\n\n```js\nimport React from 'react'\nimport renderCallback from 'react-render-callback'\n\nclass Component from React.Component {\n  state = {}\n\n  render() {\n    // can be any prop like render, component, renderHeader, ...\n    // children may be a function, a component, an element, ...\n    return renderCallback(this.props.children, this.state)\n  }\n}\n```\n\nView an example in [codesandbox.io](https://codesandbox.io/s/48k5p1r764?module=%2FApp.js).\n\n## Highlights\n\n- :package: Super tiny (~650 bytes)\n- :ok_hand: Dependency free (except for [Object.assign](https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) polyfill)\n- :electric_plug: Just Works \u003csup\u003eTM\u003c/sup\u003e\n- :crystal_ball: Tree shaking friendly (ESM, no side effects)\n- :books: Well documented\n- :100: test coverage\n- :sunny: supports React v0.14, v15 and v16\n- :family: supports rendering of\n  - [Stateless Function Components (SFC)](https://reactjs.org/docs/components-and-props.html#functional-and-class-components)\n    with one argument (the common `props` case) aka _Render Props_ aka _Function as Child_\n    or [optional with several arguments](#use-createrender-to-pass-down-several-arguments)\n  - [Class Components](https://reactjs.org/docs/react-component.html) aka _Component Injection_\n  - [Context](https://reactjs.org/docs/context.html) Provider and Consumer\n  - [Forward Refs](https://reactjs.org/docs/react-api.html#reactforwardref)\n  - [Factories](https://reactjs.org/docs/react-api.html#createfactory)\n  - [Elements](https://reactjs.org/docs/glossary.html#elements)\n    with [optional support](#use-optionscloneelement) for [cloning][clone-element] to merge props\n  - primitives like strings, numbers, arrays, ...\n  - `false`, `null`, `undefined` and `true` are returned as `null`\n    just like in [JSX](https://reactjs.org/docs/jsx-in-depth.html#booleans-null-and-undefined-are-ignored)\n\n## Table of Contents\n\n\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [API](#api)\n  - [Examples](#examples)\n- [Other Solutions](#other-solutions)\n- [Credits](#credits)\n- [Contributors](#contributors)\n- [LICENSE](#license)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n## Installation\n\nThis module is distributed via [npm][npm] which is bundled with [node][node] and\nshould be installed as one of your project's `dependencies`:\n\n```sh\nnpm install --save react-render-callback\n```\n\n\u003e This package also depends on `react`. Please make sure you\n\u003e have it installed as well.\n\nThe [Universal Module Definition (UMD)](https://github.com/umdjs/umd) is available\nvia [unpkg.com](https://unpkg.com/) and exposed as `ReactRenderCallback`.\n\n```html\n\u003cscript src=\"https://unpkg.com/react-render-callback/dist/react-render-callback.umd.min.js\"\u003e\u003c/script\u003e\n```\n\n## Usage\n\n### API\n\n#### `renderCallback([ renderable [, props [, options ] ] ])`\n\n\u003e renders the given `renderable` with `props`\n\n```js\n// esm\nimport renderCallback from 'react-render-callback'\n// commonjs\nconst renderCallback = require('react-render-callback')\n```\n\n**renderable** (optional): anything that can be rendered like a function, a component, or elements\n\n- uses [`React.createElement`][create-element]\n  for react types like\n  [class components](https://reactjs.org/docs/react-component.html),\n  [context](https://reactjs.org/docs/context.html) provider or consumer,\n  [forward refs](https://reactjs.org/docs/react-api.html#reactforwardref),\n  [factories](https://reactjs.org/docs/react-api.html#createfactory), ...\n- invokes stateless function components (SFC) respecting their\n  [`defaultProps`][default-props]\n  - not using [`React.createElement`][create-element]\n    for improved performance\n  - except the SFC has [`propTypes`](typechecking-with-proptypes) and\n    `process.env.NODE_ENV` is not `production`, in that case `React.createElement` is used to\n    enable typechecking with [PropTypes][prop-types]\n- gracefully handles other types like string, array,\n  [react elements][create-element], ...\n\n**props** (optional): to pass to `renderable`\n\n**options** (optional):\n\n- `cloneElement` (default: `false`, since: v1.1.0): allows to pass `props` to\n  the element using [`React.cloneElement`][clone-element]\n\n```js\nrenderCallback(\u003ca href=\"#bar\"\u003ebar\u003c/a\u003e, {title: 'foo'})\n// --\u003e \u003ca href=\"#bar\"\u003ebar\u003c/a\u003e\n\nrenderCallback(\u003ca href=\"#bar\"\u003ebar\u003c/a\u003e, {title: 'foo'}, {cloneElement: true})\n// --\u003e \u003ca href=\"#bar\" title=\"foo\"\u003ebar\u003c/a\u003e\n```\n\n**returns**\n\n- the created react element\n- `false`, `null`, `undefined` and `true` are returned as `null`\n  just like in [JSX](https://reactjs.org/docs/jsx-in-depth.html#booleans-null-and-undefined-are-ignored)\n- the value as is for all other values\n\n#### `createRender([ renderable [, options ] ])`\n\nsince: v1.1.0\n\n\u003e Returns a function (`(...args) =\u003e ...`) to render `renderable` with.\n\n```js\n// esm\nimport {createRender} from 'react-render-callback'\n// commonjs\nconst {createRender} = require('react-render-callback')\n```\n\nAccepts the same arguments (except `props`) as `renderCallback()`. It exists mainly\nto pre-determine (read cache) what type `renderable` is, to prevent these\nchecks on every invocation.\n\nAdditionally the returned method accepts more than one argument (since: v1.2.0).\nThis allows to provide several parameters to the `renderable`.\n\n```js\nconst renderCallback = createRender((a, b, c) =\u003e ({a, b, c}))\nrenderCallback(1, 2, 3)\n// -\u003e { a: 1, b: 2, c: 3 }\n```\n\n\u003e If the `renderable` has a `defaultProps` property only the first parameter is used\n\u003e and merged with the `defaultProps`.\n\n**returns**\n\na function (`(...args) =\u003e ...`) to render the args\n\n### Examples\n\nA basic example showing the most common use cases can be viewed/edited at [codesandbox.io](https://codesandbox.io/s/48k5p1r764?module=%2FApp.js).\n\n#### Use `options.cloneElement`\n\n[![Edit](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/mj5py581oy)\n\n\u003e This option allows to pass down `props` without to need to create a function\n\u003e within render which merges the defined and provided props.\n\n```js\nclass CountSeconds extends React.Component {\n  state = {\n    value: 0,\n  }\n\n  componentDidMount() {\n    this.timer = setInterval(() =\u003e {\n      this.setState(({value}) =\u003e ({value: value + 1}))\n    }, 1000)\n  }\n\n  componentWillUnmount() {\n    clearInterval(this.timer)\n  }\n\n  render() {\n    const {children, render = children} = this.props\n    return renderCallback(render, this.state, {cloneElement: true})\n  }\n}\n\nconst DisplayValue = ({prefix = '', value}) =\u003e `${prefix}${value}`\n\nconst App = ({prefix}) =\u003e (\n  \u003cCountSeconds\u003e\n    \u003cDisplayValue prefix={prefix} /\u003e\n  \u003c/CountSeconds\u003e\n)\n```\n\n#### Use `createRender` to pass down several arguments\n\n[![Edit](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/x3j0pxl4lw)\n\n```js\nclass CountSeconds extends React.Component {\n  state = {\n    value: 0,\n  }\n\n  reset = () =\u003e {\n    this.setState({value: 0})\n  }\n\n  componentDidMount() {\n    this.timer = setInterval(() =\u003e {\n      this.setState(({value}) =\u003e ({value: value + 1}))\n    }, 1000)\n  }\n\n  componentWillUnmount() {\n    clearInterval(this.timer)\n  }\n\n  render() {\n    const {children, render = children} = this.props\n    return createRender(render)(this.state.value, this.reset)\n  }\n}\n\nconst DisplayValue = ({prefix = '', value}) =\u003e `${prefix}${value}`\n\nconst App = () =\u003e (\n  \u003cCountSeconds\u003e\n    {(value, reset) =\u003e (\n      \u003cReact.Fragment\u003e\n        \u003cDisplayValue prefix=\"Seconds: \" value={value} /\u003e\n        \u003cbutton onClick={reset} type=\"button\"\u003e\n          reset\n        \u003c/button\u003e\n      \u003c/React.Fragment\u003e\n    )}\n  \u003c/CountSeconds\u003e\n)\n```\n\n#### Use `createRender` to interop with a library which only supports functions as render-prop\n\n[![Edit](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/1qyqwq14jq)\n\n```js\nimport Toggle from 'react-toggled'\n\nclass Toggler extends React.Component {\n  static defaultProps = {\n    onLabel: 'Toggled On',\n    offLabel: 'Toggled Off',\n  }\n\n  render() {\n    const {on, getTogglerProps, onLabel, offLabel} = this.props\n\n    return (\n      \u003cdiv\u003e\n        \u003cbutton {...getTogglerProps()}\u003eToggle me\u003c/button\u003e\n        \u003cdiv\u003e{on ? onLabel : offLabel}\u003c/div\u003e\n      \u003c/div\u003e\n    )\n  }\n}\n\nconst ToggleView = createRender(Toggler)\n\nconst App = () =\u003e \u003cToggle\u003e{ToggleView}\u003c/Toggle\u003e\n```\n\n## Other Solutions\n\n- [`render-props`](https://www.npmjs.com/package/render-props)\n- [`react-render-function`](https://www.npmjs.com/package/react-render-function)\n- [`@macklinu/render-props`](https://www.npmjs.com/package/@macklinu/render-props)\n\n## Credits\n\nA special thanks needs to go to [Kent C. Dodds](https://github.com/kentcdodds) for his great\nvideo series (\n[egghead.io](https://egghead.io/instructors/kentcdodds),\n[frontendmasters.com](https://frontendmasters.com/teachers/kentcdodds/) and\n[youtube.com](https://www.youtube.com/c/kentcdodds-vids)).\nHis projects are either used in this project ([kcd-scripts](https://github.com/kentcdodds/kcd-scripts))\nor are a template for the structure of this project ([downshift](https://github.com/paypal/downshift)).\nMake sure to [subscribe](https://buttondown.email/kentcdodds) to his newsletter.\n\n## Contributors\n\nThanks goes to these people ([emoji key][emojis]):\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section --\u003e\n\u003c!-- prettier-ignore --\u003e\n| \u003cimg src=\"https://avatars.githubusercontent.com/u/514405?v=3\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eSascha Tandel\u003c/b\u003e\u003c/sub\u003e\u003cbr /\u003e[💻](https://github.com/sastan/react-render-callback/commits?author=sastan \"Code\") [📖](https://github.com/sastan/react-render-callback/commits?author=sastan \"Documentation\") [🚇](#infra-sastan \"Infrastructure (Hosting, Build-Tools, etc)\") [⚠️](https://github.com/sastan/react-render-callback/commits?author=sastan \"Tests\") [👀](#review-sastan \"Reviewed Pull Requests\") [📝](#blog-sastan \"Blogposts\") [🐛](https://github.com/sastan/react-render-callback/issues?q=author%3Asastan \"Bug reports\") [💡](#example-sastan \"Examples\") [🤔](#ideas-sastan \"Ideas, Planning, \u0026 Feedback\") [📢](#talk-sastan \"Talks\") |\n| :---: |\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:END --\u003e\n\nThis project follows the [all-contributors][all-contributors] specification.\nContributions of any kind welcome!\n\n## LICENSE\n\nMIT\n\n[npm]: https://www.npmjs.com/\n[node]: https://nodejs.org\n[build-badge]: https://img.shields.io/travis/sastan/react-render-callback.svg?style=flat-square\n[build]: https://travis-ci.org/sastan/react-render-callback\n[coverage-badge]: https://img.shields.io/codecov/c/github/sastan/react-render-callback.svg?style=flat-square\n[coverage]: https://codecov.io/github/sastan/react-render-callback\n[version-badge]: https://img.shields.io/npm/v/react-render-callback.svg?style=flat-square\n[package]: https://www.npmjs.com/package/react-render-callback\n[npmcharts]: http://npmcharts.com/compare/react-render-callback\n[license-badge]: https://img.shields.io/npm/l/react-render-callback.svg?style=flat-square\n[license]: https://github.com/sastan/react-render-callback/blob/master/LICENSE\n[prs-badge]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square\n[prs]: http://makeapullrequest.com\n[coc-badge]: https://img.shields.io/badge/code%20of-conduct-ff69b4.svg?style=flat-square\n[coc]: https://github.com/sastan/react-render-callback/blob/master/CODE_OF_CONDUCT.md\n[gzip-badge]: http://img.badgesize.io/https://unpkg.com/react-render-callback/dist/react-render-callback.umd.min.js?compression=gzip\u0026label=umd%20gzip%20size\u0026style=flat-square\n[size-badge]: http://img.badgesize.io/https://unpkg.com/react-render-callback/dist/react-render-callback.umd.min.js?label=umd%20size\u0026style=flat-square\n[unpkg-dist]: https://unpkg.com/react-render-callback/dist/\n[module-formats-badge]: https://img.shields.io/badge/module%20formats-umd%2C%20cjs%2C%20es-green.svg?style=flat-square\n[emojis]: https://github.com/kentcdodds/all-contributors#emoji-key\n[maintainability]: https://codeclimate.com/github/sastan/react-render-callback/maintainability\n[maintainability-badge]: https://api.codeclimate.com/v1/badges/bdb9f3ea6d70b6181b33/maintainability\n[sponsored-by]: https://www.kenoxa.com\n[sponsored-by-badge]: https://img.shields.io/badge/Sponsored%20by-Kenoxa-blue.svg\n[all-contributors]: https://github.com/kentcdodds/all-contributors\n[semantic-release]: https://github.com/semantic-release/semantic-release\n[semantic-release-badge]: https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg\n[greenkeeper]: https://greenkeeper.io/\n[greenkeeper-badge]: https://badges.greenkeeper.io/sastan/react-render-callback.svg\n[semver]: http://semver.org/spec/v2.0.0.html\n[semver-badge]: https://img.shields.io/badge/SemVer-2.0.0-green.svg\n[use-a-render-prop]: https://cdb.reacttraining.com/use-a-render-prop-50de598f11ce\n[default-props]: https://reactjs.org/docs/react-component.html#defaultprops\n[render-prop]: https://reactjs.org/docs/render-props.html\n[function-as-children]: https://reactpatterns.com/#function-as-children\n[react-component]: https://reactjs.org/docs/react-component.html\n[create-element]: https://reactjs.org/docs/react-api.html#createelement\n[clone-element]: https://reactjs.org/docs/react-api.html#cloneelement\n[typechecking-with-proptypes]: https://reactjs.org/docs/typechecking-with-proptypes.html\n[prop-types]: https://www.npmjs.com/package/prop-types\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsastan%2Freact-render-callback","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsastan%2Freact-render-callback","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsastan%2Freact-render-callback/lists"}