Skip to content

Frontend Cheatsheet

Quick reference for the Fullfinity frontend framework.

my_module/
└── static/
└── src/
└── js/
└── components.js # Your components here

Components are auto-loaded based on module dependencies.

const { registry, html, useState } = window.fullfinity;
registry.component('MyComponent', function({ prop1, prop2 }) {
const [state, setState] = useState(initialValue);
return html`
<div class="my-component">
${prop1}
</div>
`;
});
<div
data-component="MyComponent"
data-props='{"prop1": "value", "prop2": {{ variable | tojson }}}'
></div>
const { html } = window.fullfinity;
// Elements
html`<div class="container">Content</div>`
// Expressions
html`<span>${value}</span>`
// Events
html`<button onClick=${handleClick}>Click</button>`
// Conditional
html`${condition && html`<div>Shown</div>`}`
html`${condition ? html`<div>A</div>` : html`<div>B</div>`}`
// Lists
html`<ul>${items.map(i => html`<li key=${i.id}>${i.name}</li>`)}</ul>`
// Nested components
html`<${ChildComponent} prop="value" />`
// Refs
html`<input ref=${inputRef} />`
const {
useState, // Local state
useEffect, // Side effects
useRef, // Mutable ref
useCallback, // Memoized callback
useMemo, // Memoized value
useStore, // Access store
useSlot, // Access slot (re-renders on change)
useLifecycle, // Lifecycle callbacks
} = window.fullfinity;
const [value, setValue] = useState(initial);
setValue(newValue); // Direct
setValue(prev => prev + 1); // Functional
// Run on every render
useEffect(() => { /* ... */ });
// Run once on mount
useEffect(() => {
// setup
return () => { /* cleanup */ };
}, []);
// Run when deps change
useEffect(() => { /* ... */ }, [dep1, dep2]);
const ref = useRef(initialValue);
ref.current = newValue; // Mutable, doesn't trigger re-render
// DOM ref
const inputRef = useRef(null);
html`<input ref=${inputRef} />`;
inputRef.current.focus();
const { useLifecycle } = window.fullfinity;
useLifecycle({
onMounted: () => console.log('Mounted'),
onUpdated: () => console.log('Updated'),
onWillUnmount: () => console.log('Unmounting')
});
const { registry, bus } = window.fullfinity;
registry.store('cart', {
items: [],
add(item) {
this.items.push(item);
fullfinity.notifyStore('cart'); // Trigger re-renders
bus.emit('cart:updated'); // Notify listeners
}
});
const { useStore } = window.fullfinity;
const cart = useStore('cart');
cart.add({ id: 1, name: 'Product' });
const { bus } = window.fullfinity;
// Subscribe
const unsubscribe = bus.on('event:name', (data) => { });
// Emit
bus.emit('event:name', { key: 'value' });
// Unsubscribe
unsubscribe();
// Once
bus.once('event:name', (data) => { });
const { patch, html } = window.fullfinity;
patch('ExistingComponent', (Original) => function(props) {
return html`
<div class="wrapper">
<${Original} ...${props} />
<div>Extra content</div>
</div>
`;
}, { id: 'my-wrapper' });
patch('Component', patcher, {
id: 'my-patch', // Required for unpatch/after
priority: 20, // Lower runs first (default: 10)
after: 'other-patch', // Run after this patch
when: () => condition // Only apply if true
});
patch('Component', (Original) => function(props) {
const modifiedProps = { ...props, newProp: 'value' };
return html`<${Original} ...${modifiedProps} />`;
}, { id: 'props-modifier' });
const { unpatch } = window.fullfinity;
unpatch('Component', 'my-patch');
const { patchMethod, unpatchMethod } = window.fullfinity;
// Multiple patches stack in priority order
patchMethod('CartWidget', 'computeTotal', function(_super, items) {
return _super(items) * 0.9; // 10% discount
}, { id: 'discount', priority: 10 });
patchMethod('CartWidget', 'computeTotal', function(_super, items) {
return _super(items) + 5; // Add shipping (runs after discount)
}, { id: 'shipping', priority: 20 });
// Remove a method patch
unpatchMethod('CartWidget', 'computeTotal', 'discount');
const { useSlot } = window.fullfinity;
registry.component('ProductCard', function(props) {
// useSlot re-renders when addons register
const extras = useSlot('ProductCard:afterPrice');
return html`
<div class="product">
<span class="price">${props.price}</span>
${extras.map(C => html`<${C} ...${props} />`)}
</div>
`;
});
registry.slot('ProductCard:afterPrice', LoyaltyBadge, {
priority: 10,
id: 'loyalty',
when: () => userHasLoyalty
});
registry.removeSlot('ProductCard:afterPrice', 'loyalty');
registry.component('DataList', function({ endpoint }) {
const { useState, useEffect, html } = window.fullfinity;
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch(endpoint)
.then(r => r.json())
.then(setData)
.finally(() => setLoading(false));
}, [endpoint]);
if (loading) return html`<div>Loading...</div>`;
return html`<ul>${data.map(i => html`<li>${i.name}</li>`)}</ul>`;
});
registry.component('Form', function({ onSubmit }) {
const { useState, html } = window.fullfinity;
const [value, setValue] = useState('');
function handleSubmit(e) {
e.preventDefault();
onSubmit(value);
}
return html`
<form onSubmit=${handleSubmit}>
<input
value=${value}
onInput=${e => setValue(e.target.value)}
/>
<button type="submit">Submit</button>
</form>
`;
});
html`<div class=${'base ' + (active ? 'active' : '')}>...</div>`
html`<div class=${['base', active && 'active'].filter(Boolean).join(' ')}>...</div>`
registry.component('Name', fn) // Register
registry.component('Name') // Get
registry.getOriginal('Name') // Get unpatched original
registry.hasComponent('Name') // Check
registry.listComponents() // List all
registry.store('name', obj) // Register
registry.store('name') // Get
registry.hasStore('name') // Check
registry.listStores() // List all
registry.slot('Name:slot', Comp, opts) // Register into slot
registry.getSlot('Name:slot') // Get slot components
registry.removeSlot('Name:slot', id) // Remove from slot
registry.listSlots('Name') // List slots
fullfinity.patch('Name', fn, opts) // Patch component
fullfinity.unpatch('Name', 'patch-id') // Remove patch
fullfinity.patchMethod('Name', 'method', fn, opts) // Patch method
fullfinity.unpatchMethod('Name', 'method', 'id') // Remove method patch
fullfinity.listPatches('Name') // List patch IDs
fullfinity.listMethodPatches('Name', 'method') // List method patch IDs
fullfinity.mountAll() // Mount all registered components
fullfinity.mountComponent('Name') // Mount specific component
fullfinity.unmount(element) // Unmount from element
fullfinity.notifyStore('name') // Trigger store re-renders
fullfinity.bus.on/emit/off/once // Event bus
// In browser console
window.fullfinity.registry.listComponents() // See all components
window.fullfinity.registry.listStores() // See all stores
window.fullfinity.registry.store('cart') // Inspect store
// Check if component exists
window.fullfinity.registry.hasComponent('ProductCard')
// Inspect patches
window.fullfinity.listPatches('ProductCard') // See patch IDs
window.fullfinity.registry.getOriginal('ProductCard') // Get unpatched
// Inspect slots
window.fullfinity.registry.listSlots('ProductCard') // See slots
window.fullfinity.registry.getSlot('ProductCard:afterPrice') // Get slot contents