├── .github
├── dependabot.yml
└── workflows
│ └── main.yaml
├── .gitignore
├── .husky
└── pre-commit
├── .lintstagedrc.json
├── .npmrc
├── .nvmrc
├── .prettierrc.json
├── DEVELOPMENT.md
├── LICENSE
├── README.md
├── lerna.json
├── package.json
├── pnpm-lock.yaml
├── pnpm-workspace.yaml
├── streamlit-component-lib-react-hooks
├── .gitignore
├── .lintstagedrc.json
├── .prettierignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── eslint.config.js
├── package.json
├── src
│ ├── ErrorBoundary.tsx
│ ├── StreamlitProvider
│ │ ├── StreamlitProvider.tsx
│ │ ├── index.ts
│ │ └── useRenderData.ts
│ ├── index.tsx
│ └── useNullableRenderData.ts
├── tsconfig.base.json
├── tsconfig.cjs.json
├── tsconfig.esm.json
└── tsconfig.json
└── template
├── LICENSE
├── MANIFEST.in
├── my_component
├── __init__.py
└── frontend
│ ├── eslint.config.js
│ ├── index.html
│ ├── package.json
│ ├── src
│ ├── MyComponent.tsx
│ └── index.tsx
│ ├── tsconfig.app.json
│ ├── tsconfig.json
│ ├── tsconfig.node.json
│ └── vite.config.ts
└── setup.py
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: npm
4 | directory: "/streamlit-component-lib-react-hooks"
5 | schedule:
6 | interval: daily
7 |
8 | - package-ecosystem: github-actions
9 | directory: "/"
10 | schedule:
11 | interval: "daily"
12 |
--------------------------------------------------------------------------------
/.github/workflows/main.yaml:
--------------------------------------------------------------------------------
1 | name: Build, Test, and Publish
2 |
3 | on:
4 | push:
5 | branches: [main]
6 | tags: ["v*"]
7 | pull_request:
8 | branches: [main]
9 |
10 | jobs:
11 | test-build:
12 | runs-on: ubuntu-latest
13 |
14 | strategy:
15 | matrix:
16 | node-version: [20, 22]
17 | # See supported Node.js release schedule at https://nodejs.org/en/about/releases/
18 |
19 | steps:
20 | - uses: actions/checkout@v4
21 | with:
22 | persist-credentials: false
23 |
24 | - uses: pnpm/action-setup@v4
25 | with:
26 | version: latest
27 | run_install: false
28 |
29 | - name: Use Node.js ${{ matrix.node-version }}
30 | uses: actions/setup-node@v4
31 | with:
32 | node-version: ${{ matrix.node-version }}
33 | cache: "pnpm"
34 |
35 | - name: Install dependencies
36 | run: pnpm install
37 |
38 | - name: Lint
39 | working-directory: streamlit-component-lib-react-hooks
40 | run: |
41 | pnpm run check:eslint
42 | pnpm run check:prettier
43 | # - run: pnpm test
44 | # working-directory: streamlit-component-lib-react-hooks
45 | - name: Build lib
46 | run: pnpm run build
47 | working-directory: streamlit-component-lib-react-hooks
48 |
49 | - name: Test building the template
50 | run: pnpm run build
51 | working-directory: template/my_component/frontend
52 |
53 | - name: Package lib
54 | working-directory: streamlit-component-lib-react-hooks
55 | run: pnpm pack
56 |
57 | - name: Upload the built tar ball as an artifact
58 | uses: actions/upload-artifact@v4
59 | if: ${{ matrix.node-version == '22' && ! startsWith(github.ref, 'refs/tags/v') }}
60 | with:
61 | path: streamlit-component-lib-react-hooks/streamlit-component-lib-react-hooks-*.tgz
62 | name: streamlit-component-lib-react-hooks-${{ github.sha }}.tgz
63 |
64 | - name: Upload the built tar ball as an artifact (when pushed with a version tag)
65 | uses: actions/upload-artifact@v4
66 | if: ${{ matrix.node-version == '22' && startsWith(github.ref, 'refs/tags/v') }}
67 | with:
68 | path: streamlit-component-lib-react-hooks/streamlit-component-lib-react-hooks-*.tgz
69 | name: streamlit-component-lib-react-hooks-${{ github.ref_name }}.tgz
70 |
71 | publish:
72 | if: ${{ startsWith(github.ref, 'refs/tags/v') }}
73 | needs: [test-build]
74 |
75 | permissions:
76 | contents: write # Necessary for creating releases: https://github.com/softprops/action-gh-release#permissions
77 |
78 | runs-on: ubuntu-latest
79 |
80 | steps:
81 | - uses: actions/checkout@v4
82 | with:
83 | persist-credentials: false
84 |
85 | - uses: pnpm/action-setup@v4
86 | with:
87 | version: latest
88 | run_install: false
89 |
90 | - name: Use Node.js ${{ matrix.node-version }}
91 | uses: actions/setup-node@v4
92 | with:
93 | node-version: ${{ matrix.node-version }}
94 | cache: "pnpm"
95 |
96 | - uses: actions/download-artifact@v4
97 | with:
98 | name: streamlit-component-lib-react-hooks-${{ github.ref_name }}.tgz
99 | path: streamlit-component-lib-react-hooks
100 |
101 | - name: Set publishing config
102 | run: pnpm config set '//registry.npmjs.org/:_authToken' "${NODE_AUTH_TOKEN}"
103 | env:
104 | NODE_AUTH_TOKEN: ${{secrets.npm_token}}
105 |
106 | # `--no-git-checks` is required for publishing a package from a workflow triggered by a tag.
107 | # See https://github.com/pnpm/pnpm/issues/5894
108 | - run: pnpm publish streamlit-component-lib-react-hooks-*.tgz --no-git-checks --access public
109 | working-directory: streamlit-component-lib-react-hooks
110 |
111 | - name: Create a new release
112 | uses: softprops/action-gh-release@v2
113 | with:
114 | files: streamlit-component-lib-react-hooks/streamlit-component-lib-react-hooks-*.tgz
115 | generate_release_notes: true
116 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Editor directories and files
2 | .vscode/*
3 | !.vscode/extensions.json
4 | .idea
5 | .DS_Store
6 | *.suo
7 | *.ntvs*
8 | *.njsproj
9 | *.sln
10 | *.sw?
11 |
12 |
13 | ### https://raw.github.com/github/gitignore/218a941be92679ce67d0484547e3e142b2f5f6f0/Python.gitignore
14 |
15 | # Byte-compiled / optimized / DLL files
16 | __pycache__/
17 | *.py[cod]
18 | *$py.class
19 |
20 | # C extensions
21 | *.so
22 |
23 | # Distribution / packaging
24 | .Python
25 | build/
26 | develop-eggs/
27 | dist/
28 | downloads/
29 | eggs/
30 | .eggs/
31 | lib/
32 | lib64/
33 | parts/
34 | sdist/
35 | var/
36 | wheels/
37 | share/python-wheels/
38 | *.egg-info/
39 | .installed.cfg
40 | *.egg
41 | MANIFEST
42 |
43 | # PyInstaller
44 | # Usually these files are written by a python script from a template
45 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
46 | *.manifest
47 | *.spec
48 |
49 | # Installer logs
50 | pip-log.txt
51 | pip-delete-this-directory.txt
52 |
53 | # Unit test / coverage reports
54 | htmlcov/
55 | .tox/
56 | .nox/
57 | .coverage
58 | .coverage.*
59 | .cache
60 | nosetests.xml
61 | coverage.xml
62 | *.cover
63 | *.py,cover
64 | .hypothesis/
65 | .pytest_cache/
66 | cover/
67 |
68 | # Translations
69 | *.mo
70 | *.pot
71 |
72 | # Django stuff:
73 | *.log
74 | local_settings.py
75 | db.sqlite3
76 | db.sqlite3-journal
77 |
78 | # Flask stuff:
79 | instance/
80 | .webassets-cache
81 |
82 | # Scrapy stuff:
83 | .scrapy
84 |
85 | # Sphinx documentation
86 | docs/_build/
87 |
88 | # PyBuilder
89 | .pybuilder/
90 | target/
91 |
92 | # Jupyter Notebook
93 | .ipynb_checkpoints
94 |
95 | # IPython
96 | profile_default/
97 | ipython_config.py
98 |
99 | # pyenv
100 | # For a library or package, you might want to ignore these files since the code is
101 | # intended to run in multiple environments; otherwise, check them in:
102 | # .python-version
103 |
104 | # pipenv
105 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
106 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
107 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
108 | # install all needed dependencies.
109 | #Pipfile.lock
110 |
111 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
112 | __pypackages__/
113 |
114 | # Celery stuff
115 | celerybeat-schedule
116 | celerybeat.pid
117 |
118 | # SageMath parsed files
119 | *.sage.py
120 |
121 | # Environments
122 | .env
123 | .venv
124 | env/
125 | venv/
126 | ENV/
127 | env.bak/
128 | venv.bak/
129 |
130 | # Spyder project settings
131 | .spyderproject
132 | .spyproject
133 |
134 | # Rope project settings
135 | .ropeproject
136 |
137 | # mkdocs documentation
138 | /site
139 |
140 | # mypy
141 | .mypy_cache/
142 | .dmypy.json
143 | dmypy.json
144 |
145 | # Pyre type checker
146 | .pyre/
147 |
148 | # pytype static type analyzer
149 | .pytype/
150 |
151 | # Cython debug symbols
152 | cython_debug/
153 |
154 |
155 | ### https://raw.github.com/github/gitignore/218a941be92679ce67d0484547e3e142b2f5f6f0/Node.gitignore
156 |
157 | # Logs
158 | logs
159 | *.log
160 | npm-debug.log*
161 | yarn-debug.log*
162 | yarn-error.log*
163 | lerna-debug.log*
164 |
165 | # Diagnostic reports (https://nodejs.org/api/report.html)
166 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
167 |
168 | # Runtime data
169 | pids
170 | *.pid
171 | *.seed
172 | *.pid.lock
173 |
174 | # Directory for instrumented libs generated by jscoverage/JSCover
175 | lib-cov
176 |
177 | # Coverage directory used by tools like istanbul
178 | coverage
179 | *.lcov
180 |
181 | # nyc test coverage
182 | .nyc_output
183 |
184 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
185 | .grunt
186 |
187 | # Bower dependency directory (https://bower.io/)
188 | bower_components
189 |
190 | # node-waf configuration
191 | .lock-wscript
192 |
193 | # Compiled binary addons (https://nodejs.org/api/addons.html)
194 | build/Release
195 |
196 | # Dependency directories
197 | node_modules/
198 | jspm_packages/
199 |
200 | # Snowpack dependency directory (https://snowpack.dev/)
201 | web_modules/
202 |
203 | # TypeScript cache
204 | *.tsbuildinfo
205 |
206 | # Optional npm cache directory
207 | .npm
208 |
209 | # Optional eslint cache
210 | .eslintcache
211 |
212 | # Microbundle cache
213 | .rpt2_cache/
214 | .rts2_cache_cjs/
215 | .rts2_cache_es/
216 | .rts2_cache_umd/
217 |
218 | # Optional REPL history
219 | .node_repl_history
220 |
221 | # Output of 'npm pack'
222 | *.tgz
223 |
224 | # Yarn Integrity file
225 | .yarn-integrity
226 |
227 | # dotenv environment variables file
228 | .env
229 | .env.test
230 |
231 | # parcel-bundler cache (https://parceljs.org/)
232 | .cache
233 | .parcel-cache
234 |
235 | # Next.js build output
236 | .next
237 | out
238 |
239 | # Nuxt.js build / generate output
240 | .nuxt
241 | dist
242 |
243 | # Gatsby files
244 | .cache/
245 | # Comment in the public line in if your project uses Gatsby and not Next.js
246 | # https://nextjs.org/blog/next-9-1#public-directory-support
247 | # public
248 |
249 | # vuepress build output
250 | .vuepress/dist
251 |
252 | # Serverless directories
253 | .serverless/
254 |
255 | # FuseBox cache
256 | .fusebox/
257 |
258 | # DynamoDB Local files
259 | .dynamodb/
260 |
261 | # TernJS port file
262 | .tern-port
263 |
264 | # Stores VSCode versions used for testing VSCode extensions
265 | .vscode-test
266 |
267 | # yarn v2
268 | .yarn/cache
269 | .yarn/unplugged
270 | .yarn/build-state.yml
271 | .yarn/install-state.gz
272 | .pnp.*
273 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | pnpm lint-staged
2 |
--------------------------------------------------------------------------------
/.lintstagedrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "*.{js,ts,jsx,tsx,html,css,md}": ["prettier --write"]
3 | }
4 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | public-hoist-pattern[]=streamlit-component-lib
2 |
--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------
1 | lts/*
2 |
--------------------------------------------------------------------------------
/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {}
2 |
--------------------------------------------------------------------------------
/DEVELOPMENT.md:
--------------------------------------------------------------------------------
1 | # Development
2 | ## Template
3 | ```shell
4 | $ cd template
5 | $ streamlit run my_component/__init__.py
6 | ```
7 |
8 | ```shell
9 | $ cd template/my_component/frontend
10 | $ pnpm start
11 | ```
12 |
13 | ## Component library
14 | ```shell
15 | $ cd streamlit-component-lib-react-hooks
16 | $ pnpm build
17 | ```
18 |
19 | # Publish
20 | ```shell
21 | $ pnpm new-version
22 | ```
23 |
24 | Then push the commit to the GitHub repository and create a new release. The CI/CD process will release the package to NPM.
25 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Yuichiro Tachibana (Tsuchiya)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # streamlit-component-template-react-hooks
2 |
3 | [](https://github.com/whitphx/streamlit-component-template-react-hooks/actions/workflows/lib-test.yaml)
4 |
5 | [](https://www.npmjs.com/package/streamlit-component-lib-react-hooks)
6 | [](https://www.npmjs.com/package/streamlit-component-lib-react-hooks)
7 |
8 |
9 | [](https://ko-fi.com/D1D2ERWFG)
10 |
11 |
12 |
13 | [](https://github.com/sponsors/whitphx)
14 |
15 | This repo contains below.
16 | * A template for creating Streamlit Components with React Hooks and functional component style: [`./template`](./template).
17 | * This is based on [the official React template](https://github.com/streamlit/component-template/tree/master/template). The original code has been copied to this repo and fixed to use React Hooks.
18 | * The source code of `streamlit-component-lib-react-hooks` npm package, which provides React-Hooks style API for Streamlit Component: [`./streamlit-component-lib-react-hooks`](streamlit-component-lib-react-hooks).
19 | * This is only for development purpose and the users of `./template` do not have to see it.
20 |
21 | ## Quickstart for the component template
22 |
23 | * Ensure you have [Python 3.6+](https://www.python.org/downloads/) and [Node.js](https://nodejs.org) installed.
24 | * Clone this repo.
25 | * Create a new Python virtual environment for the template:
26 | ```
27 | $ cd template
28 | $ python3 -m venv venv # create venv
29 | $ . venv/bin/activate # activate venv
30 | $ pip install streamlit # install streamlit
31 | ```
32 | * Initialize and run the component template frontend:
33 | ```
34 | $ cd template/my_component/frontend
35 | $ yarn # Install npm dependencies. `npm install` can be used instead.
36 | $ yarn dev # Start the Vite dev server. `npm run dev` can be used instead.
37 | ```
38 | * From a separate terminal, run the template's Streamlit app:
39 | ```
40 | $ cd template
41 | $ . venv/bin/activate # activate the venv you created earlier
42 | $ streamlit run my_component/__init__.py # run the example
43 | ```
44 | * If all goes well, you should see something like this:
45 | 
46 | * Modify the frontend code at `my_component/frontend/src/MyComponent.tsx`.
47 | * Modify the Python code at `my_component/__init__.py`.
48 |
--------------------------------------------------------------------------------
/lerna.json:
--------------------------------------------------------------------------------
1 | {
2 | "packages": [
3 | "streamlit-component-lib-react-hooks",
4 | "template/my_component/frontend"
5 | ],
6 | "version": "2.1.1",
7 | "npmClient": "pnpm"
8 | }
9 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "engines": {
4 | "node": ">=20.5.0"
5 | },
6 | "name": "streamlit-component-template-react-hooks",
7 | "devDependencies": {
8 | "@lerna-lite/cli": "^4.1.2",
9 | "@lerna-lite/version": "^4.1.2",
10 | "lint-staged": "^15.4.2",
11 | "husky": "^9.1.7",
12 | "prettier": "^3.5.3"
13 | },
14 | "scripts": {
15 | "new-version": "lerna version --sync-workspace-lock --force-publish",
16 | "prepare": "husky"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/pnpm-workspace.yaml:
--------------------------------------------------------------------------------
1 | packages:
2 | - "streamlit-component-lib-react-hooks"
3 | - "template/my_component/frontend"
4 |
--------------------------------------------------------------------------------
/streamlit-component-lib-react-hooks/.gitignore:
--------------------------------------------------------------------------------
1 | ### https://raw.github.com/github/gitignore/218a941be92679ce67d0484547e3e142b2f5f6f0/Node.gitignore
2 |
3 | # Logs
4 | logs
5 | *.log
6 | npm-debug.log*
7 | yarn-debug.log*
8 | yarn-error.log*
9 | lerna-debug.log*
10 |
11 | # Diagnostic reports (https://nodejs.org/api/report.html)
12 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
13 |
14 | # Runtime data
15 | pids
16 | *.pid
17 | *.seed
18 | *.pid.lock
19 |
20 | # Directory for instrumented libs generated by jscoverage/JSCover
21 | lib-cov
22 |
23 | # Coverage directory used by tools like istanbul
24 | coverage
25 | *.lcov
26 |
27 | # nyc test coverage
28 | .nyc_output
29 |
30 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
31 | .grunt
32 |
33 | # Bower dependency directory (https://bower.io/)
34 | bower_components
35 |
36 | # node-waf configuration
37 | .lock-wscript
38 |
39 | # Compiled binary addons (https://nodejs.org/api/addons.html)
40 | build/Release
41 |
42 | # Dependency directories
43 | node_modules/
44 | jspm_packages/
45 |
46 | # Snowpack dependency directory (https://snowpack.dev/)
47 | web_modules/
48 |
49 | # TypeScript cache
50 | *.tsbuildinfo
51 |
52 | # Optional npm cache directory
53 | .npm
54 |
55 | # Optional eslint cache
56 | .eslintcache
57 |
58 | # Microbundle cache
59 | .rpt2_cache/
60 | .rts2_cache_cjs/
61 | .rts2_cache_es/
62 | .rts2_cache_umd/
63 |
64 | # Optional REPL history
65 | .node_repl_history
66 |
67 | # Output of 'npm pack'
68 | *.tgz
69 |
70 | # Yarn Integrity file
71 | .yarn-integrity
72 |
73 | # dotenv environment variables file
74 | .env
75 | .env.test
76 |
77 | # parcel-bundler cache (https://parceljs.org/)
78 | .cache
79 | .parcel-cache
80 |
81 | # Next.js build output
82 | .next
83 | out
84 |
85 | # Nuxt.js build / generate output
86 | .nuxt
87 | dist
88 |
89 | # Gatsby files
90 | .cache/
91 | # Comment in the public line in if your project uses Gatsby and not Next.js
92 | # https://nextjs.org/blog/next-9-1#public-directory-support
93 | # public
94 |
95 | # vuepress build output
96 | .vuepress/dist
97 |
98 | # Serverless directories
99 | .serverless/
100 |
101 | # FuseBox cache
102 | .fusebox/
103 |
104 | # DynamoDB Local files
105 | .dynamodb/
106 |
107 | # TernJS port file
108 | .tern-port
109 |
110 | # Stores VSCode versions used for testing VSCode extensions
111 | .vscode-test
112 |
113 | # yarn v2
114 | .yarn/cache
115 | .yarn/unplugged
116 | .yarn/build-state.yml
117 | .yarn/install-state.gz
118 | .pnp.*
119 |
120 |
121 |
--------------------------------------------------------------------------------
/streamlit-component-lib-react-hooks/.lintstagedrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "*.{js,jsx,ts,tsx}": "pnpm --filter streamlit-component-lib-react-hooks lint-staged:eslint",
3 | "*": "pnpm --filter streamlit-component-lib-react-hooks lint-staged:prettier"
4 | }
5 |
--------------------------------------------------------------------------------
/streamlit-component-lib-react-hooks/.prettierignore:
--------------------------------------------------------------------------------
1 | dist
2 | node_modules
3 |
--------------------------------------------------------------------------------
/streamlit-component-lib-react-hooks/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to this project will be documented in this file.
4 |
5 | ## [Unreleased]
6 |
7 | ## [2.1.1] - 2025-05-22
8 |
9 | ### Fixed
10 |
11 | - Fix `README.md` and `template/MANIFEST.in`, contributed by [@F-loat](https://github.com/F-loat).
12 |
13 | ## [2.1.0] - 2025-03-13
14 |
15 | ### Changed
16 |
17 | - Support React 19.
18 |
19 | ## [2.0.10] - 2025-03-13
20 |
21 | ### Fixed
22 |
23 | - Switch to `pnpm` from `yarn`.
24 |
25 | ## [2.0.2 - 2.0.9]
26 |
27 | Skipped.
28 |
29 | ## [2.0.1] - 2025-03-13
30 |
31 | ### Fixed
32 |
33 | - Dependencies updates.
34 |
35 | ## [2.0.0] - 2025-03-13
36 |
37 | [BREAKING]: Drop support for Node.js 18.
38 | [BREAKING]: Remove React 16. Now only React 17 and 18 are supported.
39 | [BREAKING]: `streamlit-component-lib-react-hooks` is now bundled as a dual package (CJS and ESM).
40 |
41 | ## [1.2.8] - 2024-03-04
42 |
43 | Republished the same package.
44 |
45 | ## [1.2.7] - 2024-03-04
46 |
47 | Republished the same package.
48 |
49 | ## [1.2.6] - 2024-03-03
50 |
51 | Republished the same package.
52 |
53 | ## [1.2.5] - 2024-03-03
54 |
55 | **Accidentally the versions `<=1.2.4` of this package have been unpublished and cannot be restored. The same package is now published as `@streamlit/component-lib-react-hooks` starting from version `1.2.5`.**
56 |
57 | ## [1.2.4] - 2024-02-27
58 |
59 | ### Fixed
60 |
61 | - Improve the CI/CD workflow, #114.
62 | - Remove `prepare` and `prepublishOnly` hooks.
63 |
64 | ## [1.2.3]
65 |
66 | Skipped.
67 |
68 | ## [1.2.2]
69 |
70 | Skipped.
71 |
72 | ## [1.2.1] - 2024-02-27
73 |
74 | ### Changed
75 |
76 | - Remove Node 14 and 16 from the CI/CD, #111.
77 | - Update `react-scripts` to `5.0.1` and `streamlit-component-lib` to `^2.0.0`, #112.
78 |
79 | ## [1.2.0]
80 |
81 | Skipped.
82 |
83 | ## [1.1.0] - 2023-06-08
84 |
85 | ### Changed
86 |
87 | - Remove `bootstrap.min.css`, #106.
88 |
89 | ## [1.0.2] - 2022-04-24
90 |
91 | ### Fix
92 |
93 | - Include `CHANGELOG.md` in the NPM package, #53.
94 |
95 | ## [1.0.1] - 2022-04-24
96 |
97 | ### Fix
98 |
99 | - Internal package updates.
100 |
101 | ## [1.0.0] - 2022-01-26
102 |
103 | No change - just bump the version 1.0.0 as the API has been stabilized and the package is already used in some projects stably.
104 |
105 | ## [0.3.1] - 2021-11-18
106 |
107 | ### Fix
108 |
109 | - A bug that `` does not display the caught error.
110 |
111 | ## [0.3.0] - 2021-10-24
112 |
113 | ### Added
114 |
115 | - `` as an all-in-one wrapper component for React-Hooks-based components and `useRenderData` to get the `renderData` object inside the provider, #3.
116 |
117 | ## [0.2.1] - 2021-10-24
118 |
119 | ### Added
120 |
121 | - CI/CD to test and publish, #1.
122 | - Monorepo management with Lerna, #2.
123 |
124 | ## [0.2.0] - 2021-09-20
125 |
126 | ### Fix
127 |
128 | - Depending React version.
129 |
130 | ## [0.1.0] - 2021-09-20
131 |
132 | ### Added
133 |
134 | - `useStreamlit` and `ErrorBoundary`.
135 |
--------------------------------------------------------------------------------
/streamlit-component-lib-react-hooks/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Yuichiro Tachibana (Tsuchiya)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/streamlit-component-lib-react-hooks/README.md:
--------------------------------------------------------------------------------
1 | # Streamlit Component Library for React Hooks
2 |
3 | An npm package that provides support code for creating [Streamlit Components](https://docs.streamlit.io/en/stable/streamlit_components.html) with React and React Hooks.
4 |
5 | See https://github.com/whitphx/streamlit-component-template-react-hooks/tree/main/template for usage.
6 |
--------------------------------------------------------------------------------
/streamlit-component-lib-react-hooks/eslint.config.js:
--------------------------------------------------------------------------------
1 | import globals from "globals";
2 | import { defineConfig } from "eslint/config";
3 | import pluginJs from "@eslint/js";
4 | import tseslint from "typescript-eslint";
5 | import pluginReact from "eslint-plugin-react";
6 | import reactHooks from "eslint-plugin-react-hooks";
7 | import reactRefresh from "eslint-plugin-react-refresh";
8 | import pluginReactJSXRuntime from "eslint-plugin-react/configs/jsx-runtime.js";
9 |
10 | /** @type {import('eslint').Linter.Config[]} */
11 | export default defineConfig([
12 | { ignores: ["dist"] },
13 | { files: ["**/*.{js,mjs,cjs,ts,jsx,tsx}"] },
14 | { languageOptions: { globals: globals.browser } },
15 | pluginJs.configs.recommended,
16 | ...tseslint.configs.recommended,
17 | { settings: { react: { version: "detect" } } },
18 | pluginReact.configs.flat.recommended,
19 | reactHooks.configs["recommended-latest"],
20 | reactRefresh.configs.recommended,
21 | pluginReactJSXRuntime,
22 | ]);
23 |
--------------------------------------------------------------------------------
/streamlit-component-lib-react-hooks/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "streamlit-component-lib-react-hooks",
3 | "version": "2.1.1",
4 | "keywords": [
5 | "streamlit"
6 | ],
7 | "type": "module",
8 | "main": "dist/cjs/index.js",
9 | "module": "dist/esm/index.js",
10 | "types": "dist/cjs/index.d.ts",
11 | "exports": {
12 | ".": {
13 | "import": "./dist/esm/index.js",
14 | "require": "./dist/cjs/index.js",
15 | "types": "./dist/cjs/index.d.ts"
16 | }
17 | },
18 | "repository": {
19 | "type": "git",
20 | "url": "https://github.com/whitphx/streamlit-component-template-react-hooks",
21 | "directory": "streamlit-component-lib-react-hooks"
22 | },
23 | "license": "MIT",
24 | "files": [
25 | "dist"
26 | ],
27 | "scripts": {
28 | "build": "npm run build:cjs && npm run build:esm && npm run build:package-json",
29 | "build:cjs": "tsc -p tsconfig.cjs.json",
30 | "build:esm": "tsc -p tsconfig.esm.json",
31 | "build:package-json": "mkdir -p dist/cjs dist/esm && echo '{\"type\":\"commonjs\"}' > dist/cjs/package.json && echo '{\"type\":\"module\"}' > dist/esm/package.json",
32 | "fix:eslint": "eslint --fix 'src/**/*.{ts,tsx}'",
33 | "fix:prettier": "prettier --write .",
34 | "check:eslint": "eslint --fix 'src/**/*.{ts,tsx}'",
35 | "check:prettier": "prettier --check .",
36 | "lint-staged:eslint": "eslint --fix",
37 | "lint-staged:prettier": "prettier --write"
38 | },
39 | "devDependencies": {
40 | "@eslint/js": "^9.22.0",
41 | "@types/react": "^19.0.10",
42 | "@types/react-dom": "^19.0.4",
43 | "eslint": "^9.22.0",
44 | "eslint-plugin-react": "^7.37.4",
45 | "eslint-plugin-react-hooks": "^5.2.0",
46 | "eslint-plugin-react-refresh": "^0.4.19",
47 | "globals": "^16.0.0",
48 | "react": "^19.0.0",
49 | "react-dom": "^19.0.0",
50 | "streamlit-component-lib": "^2.0.0",
51 | "typescript": "^5.8.2",
52 | "typescript-eslint": "^8.26.0"
53 | },
54 | "peerDependencies": {
55 | "react": "^17.0.0 || ^18.0.0 || ^19.0.0",
56 | "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0",
57 | "streamlit-component-lib": "^2.0.0"
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/streamlit-component-lib-react-hooks/src/ErrorBoundary.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | interface ErrorBoundaryProps {
4 | children: React.ReactNode;
5 | }
6 | interface ErrorBoundaryState {
7 | error: Error | undefined;
8 | }
9 |
10 | /**
11 | * Shows errors thrown from child components.
12 | */
13 | class ErrorBoundary extends React.PureComponent<
14 | ErrorBoundaryProps,
15 | ErrorBoundaryState
16 | > {
17 | constructor(props: ErrorBoundaryProps) {
18 | super(props);
19 | this.state = { error: undefined };
20 | }
21 |
22 | static getDerivedStateFromError(error: Error) {
23 | // Update state so the next render will show the fallback UI.
24 | return { error };
25 | }
26 |
27 | render() {
28 | if (this.state.error != null) {
29 | return (
30 |
31 |
Component Error
32 | {this.state.error.message}
33 |
34 | );
35 | }
36 |
37 | return this.props.children;
38 | }
39 | }
40 |
41 | export default ErrorBoundary;
42 |
--------------------------------------------------------------------------------
/streamlit-component-lib-react-hooks/src/StreamlitProvider/StreamlitProvider.tsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from "react";
2 | import { Streamlit } from "streamlit-component-lib";
3 | import { useNullableRenderData } from "../useNullableRenderData";
4 | import ErrorBoundary from "../ErrorBoundary";
5 | import { renderDataContext } from "./useRenderData";
6 |
7 | /**
8 | * Wrapper for React-hooks-based Streamlit components.
9 | *
10 | * Bootstraps the communication interface between Streamlit and the component.
11 | */
12 | export interface StreamlitProviderProps {
13 | children: React.ReactNode;
14 | }
15 | export function StreamlitProvider(props: StreamlitProviderProps) {
16 | const renderData = useNullableRenderData();
17 |
18 | useEffect(() => {
19 | Streamlit.setFrameHeight();
20 | });
21 |
22 | // Don't render until we've gotten our first data from Streamlit.
23 | if (renderData == null) {
24 | return null;
25 | }
26 |
27 | return (
28 |
29 |
30 | {props.children}
31 |
32 |
33 | );
34 | }
35 |
--------------------------------------------------------------------------------
/streamlit-component-lib-react-hooks/src/StreamlitProvider/index.ts:
--------------------------------------------------------------------------------
1 | export { StreamlitProvider, StreamlitProviderProps } from "./StreamlitProvider";
2 | export { useRenderData } from "./useRenderData";
3 |
--------------------------------------------------------------------------------
/streamlit-component-lib-react-hooks/src/StreamlitProvider/useRenderData.ts:
--------------------------------------------------------------------------------
1 | import React, { useContext } from "react";
2 | import { RenderData } from "streamlit-component-lib";
3 |
4 | export const renderDataContext = React.createContext(
5 | undefined,
6 | );
7 |
8 | /**
9 | * Returns `RenderData` received from Streamlit.
10 | */
11 | export const useRenderData = (): RenderData => {
12 | const contextValue = useContext(renderDataContext);
13 | if (contextValue == null) {
14 | throw new Error(
15 | "useRenderData() must be used inside ",
16 | );
17 | }
18 |
19 | return contextValue;
20 | };
21 |
--------------------------------------------------------------------------------
/streamlit-component-lib-react-hooks/src/index.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable react-refresh/only-export-components */
2 | export {
3 | useRenderData,
4 | StreamlitProvider,
5 | StreamlitProviderProps,
6 | } from "./StreamlitProvider";
7 | export { useNullableRenderData } from "./useNullableRenderData";
8 |
--------------------------------------------------------------------------------
/streamlit-component-lib-react-hooks/src/useNullableRenderData.ts:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from "react";
2 | import { Streamlit, RenderData } from "streamlit-component-lib";
3 |
4 | /**
5 | * Returns `RenderData` received from Streamlit after the first render event received.
6 | */
7 | export const useNullableRenderData = (): RenderData | undefined => {
8 | const [renderData, setRenderData] = useState();
9 |
10 | useEffect(() => {
11 | const onRenderEvent = (event: Event): void => {
12 | const renderEvent = event as CustomEvent;
13 | setRenderData(renderEvent.detail);
14 | };
15 |
16 | // Set up event listeners, and signal to Streamlit that we're ready.
17 | // We won't render the component until we receive the first RENDER_EVENT.
18 | Streamlit.events.addEventListener(Streamlit.RENDER_EVENT, onRenderEvent);
19 | Streamlit.setComponentReady();
20 |
21 | const cleanup = () => {
22 | Streamlit.events.removeEventListener(
23 | Streamlit.RENDER_EVENT,
24 | onRenderEvent,
25 | );
26 | };
27 | return cleanup;
28 | }, []);
29 |
30 | return renderData;
31 | };
32 |
--------------------------------------------------------------------------------
/streamlit-component-lib-react-hooks/tsconfig.base.json:
--------------------------------------------------------------------------------
1 | {
2 | "include": ["src"],
3 | "compilerOptions": {
4 | "target": "ESNext",
5 | "jsx": "react-jsx",
6 | "moduleResolution": "node",
7 | "declaration": true,
8 | "esModuleInterop": true,
9 | "forceConsistentCasingInFileNames": true,
10 | "strict": true,
11 | "skipLibCheck": true
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/streamlit-component-lib-react-hooks/tsconfig.cjs.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.base.json",
3 | "compilerOptions": {
4 | "module": "CommonJS",
5 | "outDir": "./dist/cjs",
6 | "declarationDir": "./dist/cjs"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/streamlit-component-lib-react-hooks/tsconfig.esm.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.base.json",
3 | "compilerOptions": {
4 | "module": "ESNext",
5 | "outDir": "./dist/esm",
6 | "declarationDir": "./dist/esm"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/streamlit-component-lib-react-hooks/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.base.json",
3 | "compilerOptions": {
4 | "module": "ESNext",
5 | "noEmit": true
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/template/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Yuichiro Tachibana (Tsuchiya)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
24 | The major design pattern of this package was abstracted from Streamlit's component-template, which is subject to the same license.
25 | Here is the original copyright notice for it:
26 |
27 | Copyright (c) 2018 The Python Packaging Authority
28 |
29 | Permission is hereby granted, free of charge, to any person obtaining a copy
30 | of this software and associated documentation files (the "Software"), to deal
31 | in the Software without restriction, including without limitation the rights
32 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
33 | copies of the Software, and to permit persons to whom the Software is
34 | furnished to do so, subject to the following conditions:
35 |
36 | The above copyright notice and this permission notice shall be included in all
37 | copies or substantial portions of the Software.
38 |
39 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
40 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
42 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
43 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
44 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
45 | SOFTWARE.
46 |
--------------------------------------------------------------------------------
/template/MANIFEST.in:
--------------------------------------------------------------------------------
1 | recursive-include my_component/frontend/dist *
2 |
--------------------------------------------------------------------------------
/template/my_component/__init__.py:
--------------------------------------------------------------------------------
1 | import os
2 | import streamlit.components.v1 as components
3 |
4 | # Create a _RELEASE constant. We'll set this to False while we're developing
5 | # the component, and True when we're ready to package and distribute it.
6 | # (This is, of course, optional - there are innumerable ways to manage your
7 | # release process.)
8 | _RELEASE = False
9 |
10 | # Declare a Streamlit component. `declare_component` returns a function
11 | # that is used to create instances of the component. We're naming this
12 | # function "_component_func", with an underscore prefix, because we don't want
13 | # to expose it directly to users. Instead, we will create a custom wrapper
14 | # function, below, that will serve as our component's public API.
15 |
16 | # It's worth noting that this call to `declare_component` is the
17 | # *only thing* you need to do to create the binding between Streamlit and
18 | # your component frontend. Everything else we do in this file is simply a
19 | # best practice.
20 |
21 | if not _RELEASE:
22 | _component_func = components.declare_component(
23 | # We give the component a simple, descriptive name ("my_component"
24 | # does not fit this bill, so please choose something better for your
25 | # own component :)
26 | "my_component",
27 | # Pass `url` here to tell Streamlit that the component will be served
28 | # by the local dev server that you run via `npm run start`.
29 | # (This is useful while your component is in development.)
30 | url="http://localhost:5173",
31 | )
32 | else:
33 | # When we're distributing a production version of the component, we'll
34 | # replace the `url` param with `path`, and point it to to the component's
35 | # build directory:
36 | parent_dir = os.path.dirname(os.path.abspath(__file__))
37 | build_dir = os.path.join(parent_dir, "frontend/dist")
38 | _component_func = components.declare_component("my_component", path=build_dir)
39 |
40 |
41 | # Create a wrapper function for the component. This is an optional
42 | # best practice - we could simply expose the component function returned by
43 | # `declare_component` and call it done. The wrapper allows us to customize
44 | # our component's API: we can pre-process its input args, post-process its
45 | # output value, and add a docstring for users.
46 | def my_component(name, key=None):
47 | """Create a new instance of "my_component".
48 |
49 | Parameters
50 | ----------
51 | name: str
52 | The name of the thing we're saying hello to. The component will display
53 | the text "Hello, {name}!"
54 | key: str or None
55 | An optional key that uniquely identifies this component. If this is
56 | None, and the component's arguments are changed, the component will
57 | be re-mounted in the Streamlit frontend and lose its current state.
58 |
59 | Returns
60 | -------
61 | int
62 | The number of times the component's "Click Me" button has been clicked.
63 | (This is the value passed to `Streamlit.setComponentValue` on the
64 | frontend.)
65 |
66 | """
67 | # Call through to our private component function. Arguments we pass here
68 | # will be sent to the frontend, where they'll be available in an "args"
69 | # dictionary.
70 | #
71 | # "default" is a special argument that specifies the initial return
72 | # value of the component before the user has interacted with it.
73 | component_value = _component_func(name=name, key=key, default=0)
74 |
75 | # We could modify the value returned from the component if we wanted.
76 | # There's no need to do this in our simple example - but it's an option.
77 | return component_value
78 |
79 |
80 | # Add some test code to play with the component while it's in development.
81 | # During development, we can run this just as we would any other Streamlit
82 | # app: `$ streamlit run my_component/__init__.py`
83 | if not _RELEASE:
84 | import streamlit as st
85 |
86 | st.subheader("Component with constant args")
87 |
88 | # Create an instance of our component with a constant `name` arg, and
89 | # print its output value.
90 | num_clicks = my_component("World")
91 | st.markdown("You've clicked %s times!" % int(num_clicks))
92 |
93 | st.markdown("---")
94 | st.subheader("Component with variable args")
95 |
96 | # Create a second instance of our component whose `name` arg will vary
97 | # based on a text_input widget.
98 | #
99 | # We use the special "key" argument to assign a fixed identity to this
100 | # component instance. By default, when a component's arguments change,
101 | # it is considered a new instance and will be re-mounted on the frontend
102 | # and lose its current state. In this case, we want to vary the component's
103 | # "name" argument without having it get recreated.
104 | name_input = st.text_input("Enter a name", value="Streamlit")
105 | num_clicks = my_component(name_input, key="foo")
106 | st.markdown("You've clicked %s times!" % int(num_clicks))
107 |
--------------------------------------------------------------------------------
/template/my_component/frontend/eslint.config.js:
--------------------------------------------------------------------------------
1 | import globals from "globals";
2 | import { defineConfig } from "eslint/config";
3 | import pluginJs from "@eslint/js";
4 | import tseslint from "typescript-eslint";
5 | import pluginReact from "eslint-plugin-react";
6 | import reactHooks from "eslint-plugin-react-hooks";
7 | import reactRefresh from "eslint-plugin-react-refresh";
8 | import pluginReactJSXRuntime from "eslint-plugin-react/configs/jsx-runtime.js";
9 |
10 | /** @type {import('eslint').Linter.Config[]} */
11 | export default defineConfig([
12 | { ignores: ["dist"] },
13 | { files: ["**/*.{js,mjs,cjs,ts,jsx,tsx}"] },
14 | { languageOptions: { globals: globals.browser } },
15 | pluginJs.configs.recommended,
16 | ...tseslint.configs.recommended,
17 | { settings: { react: { version: "detect" } } },
18 | pluginReact.configs.flat.recommended,
19 | reactHooks.configs["recommended-latest"],
20 | reactRefresh.configs.recommended,
21 | pluginReactJSXRuntime,
22 | ]);
23 |
--------------------------------------------------------------------------------
/template/my_component/frontend/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Streamlit Component
5 |
6 |
7 |
8 |
9 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/template/my_component/frontend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "streamlit_component_template",
3 | "version": "2.1.1",
4 | "private": true,
5 | "type": "module",
6 | "dependencies": {
7 | "react": "^19.0.0",
8 | "react-dom": "^19.0.0",
9 | "streamlit-component-lib": "^2.0.0",
10 | "streamlit-component-lib-react-hooks": "workspace:*"
11 | },
12 | "devDependencies": {
13 | "@eslint/js": "^9.22.0",
14 | "@types/react": "^19.0.10",
15 | "@types/react-dom": "^19.0.4",
16 | "@vitejs/plugin-react": "^4.3.4",
17 | "eslint": "^9.22.0",
18 | "eslint-plugin-react": "^7.37.4",
19 | "eslint-plugin-react-hooks": "^5.2.0",
20 | "eslint-plugin-react-refresh": "^0.4.19",
21 | "globals": "^16.0.0",
22 | "typescript": "^5.8.2",
23 | "typescript-eslint": "^8.26.0",
24 | "vite": "^6.2.1"
25 | },
26 | "scripts": {
27 | "dev": "vite",
28 | "build": "vite build",
29 | "lint": "eslint ."
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/template/my_component/frontend/src/MyComponent.tsx:
--------------------------------------------------------------------------------
1 | import { Streamlit } from "streamlit-component-lib"
2 | import { useRenderData } from "streamlit-component-lib-react-hooks"
3 | import React, { useState, useCallback } from "react"
4 |
5 | /**
6 | * This is a React-based component template with functional component and hooks.
7 | */
8 | function MyComponent() {
9 | // "useRenderData" returns the renderData passed from Python.
10 | const renderData = useRenderData()
11 |
12 | const [numClicks, setNumClicks] = useState(0)
13 | const [isFocused, setIsFocused] = useState(false)
14 |
15 | /** Click handler for our "Click Me!" button. */
16 | const onClicked = useCallback(() => {
17 | // Increment `numClicks` state, and pass the new value back to
18 | // Streamlit via `Streamlit.setComponentValue`.
19 | const newValue = numClicks + 1
20 | setNumClicks(newValue)
21 | Streamlit.setComponentValue(newValue)
22 | }, [numClicks])
23 |
24 | /** Focus handler for our "Click Me!" button. */
25 | const onFocus = useCallback(() => {
26 | setIsFocused(true)
27 | }, [])
28 |
29 | /** Blur handler for our "Click Me!" button. */
30 | const onBlur = useCallback(() => {
31 | setIsFocused(false)
32 | }, [])
33 |
34 | // Arguments that are passed to the plugin in Python are accessible
35 | // via `renderData.args`. Here, we access the "name" arg.
36 | const name = renderData.args["name"]
37 |
38 | // Streamlit sends us a theme object via renderData that we can use to ensure
39 | // that our component has visuals that match the active theme in a
40 | // streamlit app.
41 | const theme = renderData.theme
42 | const style: React.CSSProperties = {}
43 |
44 | // Maintain compatibility with older versions of Streamlit that don't send
45 | // a theme object.
46 | if (theme) {
47 | // Use the theme object to style our button border. Alternatively, the
48 | // theme style is defined in CSS vars.
49 | const borderStyling = `1px solid ${isFocused ? theme.primaryColor : "gray"}`
50 | style.border = borderStyling
51 | style.outline = borderStyling
52 | }
53 |
54 | // Show a button and some text.
55 | // When the button is clicked, we'll increment our "numClicks" state
56 | // variable, and send its new value back to Streamlit, where it'll
57 | // be available to the Python program.
58 | return (
59 |
60 | Hello, {name}!
61 |
70 |
71 | )
72 | }
73 |
74 | export default MyComponent
75 |
--------------------------------------------------------------------------------
/template/my_component/frontend/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { createRoot } from "react-dom/client";
3 | import { StreamlitProvider } from "streamlit-component-lib-react-hooks";
4 | import MyComponent from "./MyComponent";
5 |
6 | createRoot(document.getElementById("root")!).render(
7 |
8 |
9 |
10 |
11 | ,
12 | );
13 |
--------------------------------------------------------------------------------
/template/my_component/frontend/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
4 | "target": "ES2020",
5 | "useDefineForClassFields": true,
6 | "lib": ["ES2020", "DOM", "DOM.Iterable"],
7 | "module": "ESNext",
8 | "skipLibCheck": true,
9 |
10 | /* Bundler mode */
11 | "moduleResolution": "Bundler",
12 | "allowImportingTsExtensions": true,
13 | "isolatedModules": true,
14 | "moduleDetection": "force",
15 | "noEmit": true,
16 | "jsx": "react-jsx",
17 | "esModuleInterop": true,
18 |
19 | /* Linting */
20 | "strict": true,
21 | "noUnusedLocals": true,
22 | "noUnusedParameters": true,
23 | "noFallthroughCasesInSwitch": true,
24 | "noUncheckedSideEffectImports": true
25 | },
26 | "include": ["src"]
27 | }
28 |
--------------------------------------------------------------------------------
/template/my_component/frontend/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "files": [],
3 | "references": [
4 | { "path": "./tsconfig.app.json" },
5 | { "path": "./tsconfig.node.json" }
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/template/my_component/frontend/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
4 | "target": "ES2022",
5 | "lib": ["ES2023"],
6 | "module": "ESNext",
7 | "skipLibCheck": true,
8 |
9 | /* Bundler mode */
10 | "moduleResolution": "bundler",
11 | "allowImportingTsExtensions": true,
12 | "isolatedModules": true,
13 | "moduleDetection": "force",
14 | "noEmit": true,
15 |
16 | /* Linting */
17 | "strict": true,
18 | "noUnusedLocals": true,
19 | "noUnusedParameters": true,
20 | "noFallthroughCasesInSwitch": true,
21 | "noUncheckedSideEffectImports": true
22 | },
23 | "include": ["vite.config.ts"]
24 | }
25 |
--------------------------------------------------------------------------------
/template/my_component/frontend/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "vite";
2 | import react from "@vitejs/plugin-react";
3 |
4 | export default defineConfig({
5 | base: "./",
6 | plugins: [react()],
7 | });
8 |
--------------------------------------------------------------------------------
/template/setup.py:
--------------------------------------------------------------------------------
1 | import setuptools
2 |
3 | setuptools.setup(
4 | name="streamlit-custom-component",
5 | version="0.0.1",
6 | author="",
7 | author_email="",
8 | description="",
9 | long_description="",
10 | long_description_content_type="text/plain",
11 | url="",
12 | packages=setuptools.find_packages(),
13 | include_package_data=True,
14 | classifiers=[],
15 | python_requires=">=3.6",
16 | install_requires=[
17 | # By definition, a Custom Component depends on Streamlit.
18 | # If your component has other Python dependencies, list
19 | # them here.
20 | "streamlit >= 0.63",
21 | ],
22 | )
23 |
--------------------------------------------------------------------------------