JavaScript Assets
NRP repositories support two approaches for client-side interactivity: simple/vanilla JavaScript for lightweight DOM manipulation, and React for complex stateful UI components.
Choosing the Right Approach
All JavaScript in NRP repositories is bundled through Webpack/RSpack (see Webpack Configuration), regardless of whether you use vanilla JS or React. Start with vanilla JavaScript for simple use cases — it’s easier to implement for lightweight interactions. Introduce React when you need state management, component reusability, or any complex interfaces.
| Scenario | Use |
|---|---|
| Simple form validation, toggles, mobile menus | Vanilla JS |
| One-off event listeners (click, scroll) | Vanilla JS |
| jQuery plugins or small interactions | Vanilla JS |
| Complex forms with validation | React |
| State-driven interfaces (filters, tabs) | React |
| Datasets with search/filter/sort | React |
File Organization
JavaScript assets are organized within each UI module, typically with a nested folder structure that mirrors the module name under ui/<module>/semantic-ui/js/<module>/:
- webpack.py
- index.js
- index.js
- filters.js
- webpack.py
- Module folders - Each UI module has its own
webpack.pyandsemantic-ui/js/directory semantic-ui/js/<module>/- JavaScript folder named after the module
Quick Start
Adding Vanilla JavaScript
- Create a JS file for your feature in
ui/<module>/semantic-ui/js/<module>/:
// ui/myfeature/semantic-ui/js/myfeature/home-page-search.js
document.addEventListener('DOMContentLoaded', () => {
const searchInput = document.querySelector('input.form-control');
if (searchInput) {
searchInput.addEventListener('keydown', (e) => {
if (e.key === 'Enter') {
window.location.href = `/search?q=${encodeURIComponent(searchInput.value)}`;
}
});
}
});- Register the entry point in your module’s
webpack.py(see Webpack Configuration):
from invenio_assets.webpack import WebpackThemeBundle
theme = WebpackThemeBundle(
__name__,
".",
default="semantic-ui",
themes={
"semantic-ui": dict(
entry={
"home-page-search": "./js/myfeature/search/home-page-search.js", # ← Add your entry point here
},
)
}
)- Include the webpack bundle in your Jinja/JinjaX template:
{%- block javascript %}
{{ webpack['home-page-search'] }}
{%- endblock %}Adding a React app
- Include a
divwith your target id in the Jinja or JinjaX template where you want the React app to appear:
<div id="search-root"></div>- Create your React app in
ui/<module>/semantic-ui/js/<module>/:
// ui/mymodel/semantic-ui/js/mymodel/search/search.js
import ReactDOM from "react-dom";
import { SearchApp } from './SearchApp';
document.addEventListener('DOMContentLoaded', () => {
const rootElement = document.getElementById('search-root');
if (rootElement) {
ReactDOM.render(<SearchApp />, rootElement);
}
});- Register the entry point in your module’s
webpack.py(see Webpack Configuration):
from invenio_assets.webpack import WebpackThemeBundle
theme = WebpackThemeBundle(
__name__,
".",
default="semantic-ui",
themes={
"semantic-ui": dict(
entry={
"search": "./js/mymodel/search/search.js", # ← Add your entry point here
},
)
}
)- Include the webpack bundle in your Jinja/JinjaX template:
{%- block javascript %}
{{ webpack['search.js'] }}
{%- endblock %}The webpack Jinja variable provides access to all bundled JavaScript assets. Use the entry point name (from step 3) with .js appended to include the bundle entry.