refs Plugin
The refs plugin is a built-in Coralite helper that provides runtime DOM element access. It allows template scripts to safely access and manipulate DOM elements by their ref attributes. The framework handles automatic unique ID generation by assigning the generated ID to the ref attribute, leaving the standard id attribute intact.
Basic Usage #
Here's the complete workflow for using refs:
<template id="form-component">
<form>
<input type="text" ref="username" placeholder="Username"></input>
<input type="password" ref="password" placeholder="Password"></input>
<button type="button" ref="submitBtn">Submit</button>
</form>
</template>
<script type="module">
import { defineComponent } from 'coralite'
export default defineComponent({
client: {
script: (context) => {
const { helpers } = context
const refs = helpers.refs
const username = refs('username')
const password = refs('password')
const submitBtn = refs('submitBtn')
submitBtn.addEventListener('click', () => {
if (username.value && password.value) {
console.log('Login:', username.value)
// Handle form submission
} else {
alert('Please fill all fields')
}
})
}
}
})
</script>
Complete Examples #
Interactive Counter #
<template id="counter">
<div class="counter">
<h2>Count: {{ count }}</h2>
<button type="button" ref="increment">+</button>
<button type="button" ref="decrement">-</button>
<button type="button" ref="reset">Reset</button>
</div>
</template>
<script type="module">
import { defineComponent } from 'coralite'
export default defineComponent({
tokens: {
count: ({ initial }) => parseInt(initial) || 0
},
client: {
script: (context) => {
const { helpers, root, values } = context
const refs = helpers.refs
const increment = refs('increment')
const decrement = refs('decrement')
const reset = refs('reset')
let count = values.count
const counterDisplay = root.querySelector('h2')
increment.addEventListener('click', () => {
count++
counterDisplay.textContent = `Count: ${count}`
})
decrement.addEventListener('click', () => {
count--
counterDisplay.textContent = `Count: ${count}`
})
reset.addEventListener('click', () => {
count = 0
counterDisplay.textContent = `Count: ${count}`
})
}
}
})
</script>
Dynamic Form Validation #
<template id="signup-form">
<form>
<div>
<input type="email" ref="email" placeholder="Email"></input>
<span ref="emailError" class="error"></span>
</div>
<div>
<input type="password" ref="password" placeholder="Password"></input>
<span ref="passwordError" class="error"></span>
</div>
<button type="button" ref="submitBtn">Sign Up</button>
</form>
</template>
<script type="module">
import { defineComponent } from 'coralite'
export default defineComponent({
client: {
script: (context) => {
const { helpers } = context
const refs = helpers.refs
const email = refs('email')
const password = refs('password')
const emailError = refs('emailError')
const passwordError = refs('passwordError')
const submitBtn = refs('submitBtn')
const validateEmail = (email) => {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)
}
const validatePassword = (password) => {
return password.length >= 8
}
submitBtn.addEventListener('click', () => {
let valid = true
// Validate email
if (!validateEmail(email.value)) {
emailError.textContent = 'Invalid email format'
valid = false
} else {
emailError.textContent = ''
}
// Validate password
if (!validatePassword(password.value)) {
passwordError.textContent = 'Password must be 8+ characters'
valid = false
} else {
passwordError.textContent = ''
}
if (valid) {
console.log('Form submitted:', email.value)
// Submit form
}
})
}
}
})
</script>
Tabbed Interface #
<template id="tabs">
<div class="tabs">
<div class="tab-buttons">
<button type="button" ref="tab1">Tab 1</button>
<button type="button" ref="tab2">Tab 2</button>
<button type="button" ref="tab3">Tab 3</button>
</div>
<div class="tab-content">
<div ref="content1">Content 1</div>
<div ref="content2" style="display:none">Content 2</div>
<div ref="content3" style="display:none">Content 3</div>
</div>
</div>
</template>
<script type="module">
import { defineComponent } from 'coralite'
export default defineComponent({
client: {
script: (context) => {
const { helpers } = context
const refs = helpers.refs
const buttons = [refs('tab1'), refs('tab2'), refs('tab3')]
const contents = [refs('content1'), refs('content2'), refs('content3')]
buttons.forEach((btn, index) => {
btn.addEventListener('click', () => {
// Hide all contents
contents.forEach(content => {
content.style.display = 'none'
})
// Show selected content
contents[index].style.display = 'block'
// Update button states
buttons.forEach(b => b.classList.remove('active'))
btn.classList.add('active')
})
})
}
}
})
</script>
Key Points #
- Runtime Access:
helpers.refs('refName')gets DOM elements - Automatic Caching: Elements cached after first access
- Safe Queries: Returns null if element not found
- Under the Hood: Framework assigns the generated unique ID to the
refattribute and queries it viaroot.querySelector('[ref="..."]'). E2E tests should query this compiled ref attribute directly (e.g.,[ref="my-component__btn-0"]).