Prisma PHP Reactivity
Prisma PHP Reactivity allows you to write dynamic templates using {{ expression }}
syntax. These expressions are evaluated to render state or computed values without side effects.
Expression Rules
Inside {{ ... }}
, only pure expressions are allowed. These include reading state, performing computations, and string formatting. Any mutation or imperative code is forbidden.
Allowed vs. Not Allowed
Allowed in {{ }} | Not Allowed in {{ }} |
---|---|
Read-only state access{{ title }} , {{ user.name }}
|
Assignments & mutations{{ title = 'hello' }}
|
Arithmetic expressions{{ count + 1 }}
{{ Number(count) * 2 }}
|
Variable declarations{{ const x = 1 }}
|
Logical & ternary expressions{{ isActive ? 'Yes' : 'No' }}
|
Function definitions or classes |
String methods{{ name.length }}
{{ name.trim() }}
|
Multiple expressions or semicolons{{ a = 1; b = 2 }}
|
Optional chaining{{ user?.email }}
|
Impure functions{{ alert('Hi') }}
|
Nullish coalescing{{ title ?? 'default' }}
{{ title && 'default' }}
{{ title || 'default' }}
|
Modifying global/built-in objects |
Pure function calls{{ formatDate(date) }}
|
|
Inline template literals with backticks{{ `Username: ${user.name}` }}
{{ `Username length: ${user.name.length}` }}
{{ `Username UPPERCASE: ${user.name.toUpperCase()}` }}
|
Multiline template literals{{ `Line 1\nLine 2` }}
|
β οΈ Reserved Variable Names
When using reactivity with {{ jsVariable }}
syntax, avoid naming your variables with commonly used HTML attributes or global DOM properties. These may cause unexpected behavior due to browser-native conflicts or overwritten properties during binding.
β Do Not Use These Reserved Names
Reserved Name | Why It's Problematic |
---|---|
class |
Conflicts with HTML class attribute; use className or customClass instead. |
name |
Clashes with form controls and global window.name . |
id |
Conflicts with window.id and DOM element identifiers. |
value |
Conflicts with input/textarea value bindings. |
type |
Can interfere with buttons, inputs, and script tags. |
length |
Often misused when working with strings or arrays. |
constructor |
Reserved by JavaScript objects; accessing it may expose prototype. |
toString |
Overwrites built-in object behavior and string conversion. |
children |
Reserved in many UI frameworks and DOM traversal. |
If you use any of these by accident, Prisma PHP will attempt to handle them safely using proxies and fallback defaults. However, for clarity and stability, itβs best to rename your variables when possible. Use prefixes like userClass
, formName
, or textValue
.
Internally, Prisma PHP Reactivity analyzes expressions with a custom parser that extracts identifiers using:
// TypeScript: expression variable parser
expr.match(/\b[a-zA-Z_][a-zA-Z0-9_]*\b/g)
Avoiding reserved or ambiguous names prevents false matches and guarantees proper reactivity across components.
Examples
{{ user.name }}
<h1>Welcome, {{ user.name }}!</h1>
<p>Length: {{ textCount.length }}!</p>
<p>Balance: {{ Number(account.balance) + Number(bonus) }}</p>
<p>Status: {{ isActive ? 'Active' : 'Inactive' }}</p>
<p class="bg-red-500 {{ textColor }}"></p>
π§ͺ Example: Using Backticks with Expressions
You can use JavaScript template literals inside expressions as long as they remain on a single line. This is especially helpful when combining strings and variables.
{{ `Username: ${user.name}` }}
{{ `Balance: ${Number(balance).toFixed(2)}` }}
Avoid using line breaks inside the backticks. If you need multiline output, use multiple elements instead of a multiline template string.
When you use {{ jsVariable }}, the variable becomes globally accessible via window.jsVariable
and pphp.props.jsVariable
. Inside a function, you can retrieve its value using pphp.props.jsVariable
. To update the variable and trigger a re-render of the template, simply assign a new value to pphp.props.jsVariable
, like pphp.props.jsVariable = 'new value'
.
Initialize Variable
{{ user.name }}
<h1>Welcome, {{ user.name }}!</h1>
<p>Length: {{ textCount.length }}!</p>
<p>Balance: {{ Number(account.balance) + Number(bonus) }}</p>
<p>Status: {{ isActive ? 'Active' : 'Inactive' }}</p>
<p class="bg-red-500 {{ textColor }}"></p>
<script>
pphp.props.user = { name: 'John Doe' }; // Initialize the variable
pphp.props.textCount = 'Hello World'; // Initialize the variable
pphp.props.account = { balance: 1000 }; // Initialize the variable
pphp.props.isActive = true; // Initialize the variable
pphp.props.textColor = 'text-white'; // Initialize the variable
// global window version
window.user = { name: 'John Doe' }; // Initialize the variable
window.textCount = 'Hello World'; // Initialize the variable
window.account = { balance: 1000 }; // Initialize the variable
window.isActive = true; // Initialize the variable
window.textColor = 'text-white'; // Initialize the variable
// Shorthand version
user = { name: 'John Doe' }; // Initialize the variable
textCount = 'Hello World'; // Initialize the variable
account = { balance: 1000 }; // Initialize the variable
isActive = true; // Initialize the variable
textColor = 'text-white'; // Initialize the variable
</script>
π₯ Example: Getting Input Value
<input type="text" onchange="inputValue = this.value" class="input input-bordered" />
<p>You entered: {{ inputValue }}</p>
<button onclick="getInputValue">Click Me!</button>
<script>
function getInputValue() {
const inputValue = pphp.props.inputValue; // Access the input value
console.log('Input Value:', inputValue); // Do something with it
}
</script>
Special Attributes: pp-bind
and pp-bind-*
Prisma PHP Reactivity introduces special attributes for dynamic DOM bindings:
pp-bind
and
pp-bind-*
.
These enable you to bind JavaScript variables to specific DOM properties and attributes in a declarative way, by default this will replace the content of the element with the value of the variable.
NOTE: When using pp-bind-class
, the existing class
attribute will be replaced entirely by the value of the JavaScript variable. If you want to preserve existing classes and append the variable's value, consider using a template like <p class="bg-amber-200 {{ jsVariable }}"></p>
instead.
π¬ pp-bind="jsVariable"
This binds the content of the element directly to the specified JavaScript variable. It sets the textContent of the element.
<span pp-bind="username"></span>
// sets: span.textContent = username
π§ pp-bind-*
(Dynamic Attribute Bindings)
The wildcard asterisk (*
) in pp-bind-*
allows you to bind any specific attribute or property of a DOM element.
pp-bind-value="age"
β setselement.value = age
pp-bind-checked="isChecked"
β setselement.checked = isChecked
pp-bind-class="dynamicClass"
β updateselement.className
pp-bind-disabled="isDisabled"
β setselement.disabled = isDisabled
π Key Differences
Feature | pp-bind |
pp-bind-* |
---|---|---|
Target | Element's textContent |
Specific attribute or property |
Use Case | Display text | Input, checkbox, class, disabled, etc. |
Example | <span pp-bind="username"></span> |
<input pp-bind-value="username" /> |
π§ͺ Live Example
<input type="text" pp-bind-value="userInput" />
<p pp-bind="userInput"></p>
<input type="checkbox" pp-bind-checked="acceptTerms" />
<div pp-bind-class="cardClass">Card</div>
These bindings ensure your DOM elements always stay in sync with your reactive state.
Setting Variables Using Events
In Prisma PHP Reactivity, you can directly update your reactive variables using standard DOM events such as onclick
, onchange
, oninput
, and more. Once a variable is updated, any element that uses it via {{ }}
or pp-bind
will automatically reflect the change.
π₯ Input Binding
Use an onchange
or oninput
event to assign the value to your variable.
<input type="text" onchange="name = this.value" class="input input-bordered" />
<p>Your name is: {{ name }}</p>
βοΈ Checkbox Binding
Combine pp-bind-checked
with an event to toggle booleans.
<input type="checkbox" pp-bind-checked="active" onchange="active = this.checked" />
<p>Account is: {{ active ? 'Active' : 'Inactive' }}</p>
π±οΈ Toggle on Button Click
A button click can toggle values or modify them in any way using pure expressions.
<button onclick="active = !active" class="btn btn-primary">
Toggle Active
</button>
<p>Status: {{ active ? 'Enabled' : 'Disabled' }}</p>
π§ͺ More Examples
<!-- Updating a number -->
<input type="number" onchange="age = +this.value" class="input input-bordered" />
<p>Age: {{ age }}</p>
<!-- Dropdown selector -->
<select onchange="role = this.value" class="select select-bordered">
<option value="admin">Admin</option>
<option value="editor">Editor</option>
<option value="viewer">Viewer</option>
</select>
<p>Selected Role: {{ role }}</p>
<!-- Toggle visibility using a boolean -->
<button onclick="showInfo = !showInfo" class="btn btn-info">
Toggle Info
</button>
<div pp-bind-class="showInfo ? 'block' : 'hidden'" class="mt-2">
Extra info is now visible!
</div>
Any JavaScript expression that updates a variable will automatically re-render all related reactive bindings. Keep expressions pure and declarative for best results.
NOTE: If you need to apply multiple behaviors, it is recommended to use a JavaScript function. For example, you can set attributes like pp-bind="setText"
and pp-bind-class="appendClass"
. Within the function triggered by an event (e.g., onclick
), you can update the variable values and class names. Use pphp.props.variable
to set the desired properties dynamically.
π§© Updating Nested Variables
Prisma PHP Reactivity supports nested object structures. When working with deeply nested variables (e.g., userModal.open
), you can use the helper method setNestedProperty
to update them safely and dynamically.
π§ setNestedProperty(obj, path, value)
This method updates a nested property in a reactive object based on a dot-separated path.
setNestedProperty(pphp.props, 'userModal.open', true);
This is equivalent to:
pphp.props.userModal = pphp.props.userModal || {};
pphp.props.userModal.open = true;
π Example Use Case
Useful when updating deeply nested values based on dynamic strings or events:
<button onclick="setNestedProperty(pphp.props, 'modalSettings.show', true)" class="btn btn-info">
Open Modal
</button>
<dialog open="{{ modalSettings.show }}" onOpenChange="modalSettings.show">
Modal content here
</dialog>
π§ Function Definition
/**
* Updates a nested property given a dot-separated path.
*
* @param obj - The object to update.
* @param path - Dot-separated property path (e.g., 'userModal.open').
* @param value - The value to assign.
*/
function setNestedProperty(obj, path, value) {
const keys = path.split(".");
let current = obj;
for (let i = 0; i < keys.length - 1; i++) {
if (!(keys[i] in current)) {
current[keys[i]] = {};
}
current = current[keys[i]];
}
current[keys[keys.length - 1]] = value;
}
This method simplifies updating deeply nested properties without manually traversing each level. It ensures clean and dynamic assignment of values within the pphp.props
reactive object. For example, when creating reusable components like dialogs or modals, you can manage their state (e.g., open or closed) dynamically. By using attributes like open="{{ modalSettings.show }}"
and onOpenChange="modalSettings.show"
, you can retrieve the variable name via onOpenChange
and update its value with setNestedProperty(pphp.props, onOpenChange, true)
. This approach ensures the modal opens by setting the state to true
, providing a seamless way to manage component behavior.
Conclusion
By restricting {{ ... }}
to pure expressions only, Prisma PHP Reactivity ensures your templates stay safe, fast, and easy to reason about. Avoid side effects, and your UI will stay in sync with the state like magic β¨.