Skip to content

Magic Properties

SenangStart Actions provides special "magic" properties that are available within any ss-data scope. These properties give you access to useful functionality without additional setup.

$refs

Access DOM elements marked with ss-ref.

html
<div ss-data="{}">
  <input type="text" ss-ref="nameInput">
  <button ss-on:click="$refs.nameInput.focus()">Focus</button>
  <button ss-on:click="$refs.nameInput.value = ''">Clear</button>
  <button ss-on:click="alert($refs.nameInput.value)">Get Value</button>
</div>

Common Uses

html
<div ss-data="{}">
  <!-- Focus management -->
  <input ss-ref="email" ss-on:keyup.enter="$refs.password.focus()">
  <input ss-ref="password" type="password">
  
  <!-- Form reset -->
  <form ss-ref="form">
    <input name="field1">
    <button type="button" ss-on:click="$refs.form.reset()">Reset</button>
  </form>
  
  <!-- Media control -->
  <video ss-ref="video" src="video.mp4"></video>
  <button ss-on:click="$refs.video.play()">Play</button>
  <button ss-on:click="$refs.video.pause()">Pause</button>
  
  <!-- Scroll to element -->
  <button ss-on:click="$refs.section.scrollIntoView({ behavior: 'smooth' })">
    Go to Section
  </button>
  <div ss-ref="section">Target Section</div>
</div>

$store

Access global stores registered with SenangStart.store().

Registering a Store

javascript
SenangStart.store('user', {
  name: 'Guest',
  isLoggedIn: false,
  login(name) {
    this.name = name
    this.isLoggedIn = true
  },
  logout() {
    this.name = 'Guest'
    this.isLoggedIn = false
  }
})

SenangStart.store('cart', {
  items: [],
  add(item) {
    this.items.push(item)
  },
  get total() {
    return this.items.reduce((sum, item) => sum + item.price, 0)
  }
})

Using in HTML

html
<div ss-data="{}">
  <!-- Read store values -->
  <p ss-text="'Welcome, ' + $store.user.name"></p>
  
  <!-- Call store methods -->
  <button ss-show="!$store.user.isLoggedIn" 
          ss-on:click="$store.user.login('John')">
    Login
  </button>
  <button ss-show="$store.user.isLoggedIn"
          ss-on:click="$store.user.logout()">
    Logout
  </button>
  
  <!-- Access computed properties -->
  <p ss-text="'Cart total: $' + $store.cart.total"></p>
</div>

Cross-Component Communication

html
<!-- Header component -->
<header ss-data="{}">
  <span ss-text="$store.cart.items.length + ' items'"></span>
</header>

<!-- Product listing -->
<div ss-data="{ products: [...] }">
  <template ss-for="product in products">
    <div>
      <span ss-text="product.name"></span>
      <button ss-on:click="$store.cart.add(product)">Add to Cart</button>
    </div>
  </template>
</div>

<!-- Cart sidebar -->
<aside ss-data="{}">
  <template ss-for="item in $store.cart.items">
    <div ss-text="item.name + ' - $' + item.price"></div>
  </template>
  <p ss-text="'Total: $' + $store.cart.total"></p>
</aside>

$el

Reference to the current DOM element.

html
<div ss-data="{}">
  <!-- Toggle class on self -->
  <div ss-on:click="$el.classList.toggle('active')">
    Click to toggle active class
  </div>
  
  <!-- Get element dimensions -->
  <div ss-on:click="alert('Width: ' + $el.offsetWidth)">
    Click to see width
  </div>
  
  <!-- Style manipulation -->
  <div ss-on:mouseenter="$el.style.backgroundColor = 'yellow'"
       ss-on:mouseleave="$el.style.backgroundColor = ''">
    Hover me
  </div>
</div>

$event

Access the native DOM event object in event handlers.

html
<div ss-data="{ lastClick: '' }">
  <!-- Get event properties -->
  <div ss-on:click="lastClick = 'X: ' + $event.clientX + ', Y: ' + $event.clientY">
    Click anywhere
  </div>
  <p ss-text="lastClick"></p>
  
  <!-- Prevent default explicitly -->
  <a href="/somewhere" ss-on:click="$event.preventDefault(); handleClick()">
    Custom Link
  </a>
  
  <!-- Access input value -->
  <input ss-on:input="console.log($event.target.value)">
  
  <!-- Keyboard events -->
  <input ss-on:keydown="if ($event.key === 'Enter') submit()">
</div>

$dispatch

Dispatch custom DOM events that bubble up the tree.

Basic Usage

html
<div ss-data="{ message: '' }" ss-on:notify="message = $event.detail.text">
  <p ss-text="message || 'No message yet'"></p>
  
  <button ss-on:click="$dispatch('notify', { text: 'Hello from button!' })">
    Send Message
  </button>
</div>

Parent-Child Communication

html
<!-- Parent -->
<div ss-data="{ items: [] }" ss-on:item-added="items.push($event.detail)">
  <h2>Items: <span ss-text="items.length"></span></h2>
  <ul>
    <template ss-for="item in items">
      <li ss-text="item.name"></li>
    </template>
  </ul>
  
  <!-- Child component -->
  <div ss-data="{ newItem: '' }">
    <input ss-model="newItem" placeholder="Item name">
    <button ss-on:click="
      if (newItem) {
        $dispatch('item-added', { name: newItem });
        newItem = ''
      }
    ">Add Item</button>
  </div>
</div>
html
<div ss-data="{ showModal: false }" ss-on:close-modal="showModal = false">
  <button ss-on:click="showModal = true">Open Modal</button>
  
  <template ss-if="showModal">
    <div class="modal-backdrop">
      <div class="modal" ss-data="{}">
        <h2>Modal Title</h2>
        <p>Modal content</p>
        <button ss-on:click="$dispatch('close-modal')">Close</button>
      </div>
    </div>
  </template>
</div>

Live Example

html
<!DOCTYPE html>
<html>
<head>
  <title>Magic Properties Example</title>
  <style>
    .notification { 
      padding: 1rem; 
      background: #d4edda; 
      border-radius: 4px;
      margin: 0.5rem 0;
    }
  </style>
</head>
<body>
  <script>
    // Register global store
    SenangStart.store('notifications', {
      items: [],
      add(message) {
        this.items.push({ id: Date.now(), message })
      },
      remove(id) {
        this.items = this.items.filter(n => n.id !== id)
      }
    })
  </script>

  <!-- Notification display -->
  <div ss-data="{}">
    <h3>Notifications</h3>
    <template ss-for="notification in $store.notifications.items">
      <div class="notification">
        <span ss-text="notification.message"></span>
        <button ss-on:click="$store.notifications.remove(notification.id)">×</button>
      </div>
    </template>
  </div>

  <!-- Form that adds notifications -->
  <div ss-data="{ message: '' }" 
       ss-on:notify="$store.notifications.add($event.detail.message)">
    <input ss-ref="input" ss-model="message" placeholder="Enter message">
    <button ss-on:click="
      if (message) {
        $dispatch('notify', { message: message });
        message = '';
        $refs.input.focus()
      }
    ">Add Notification</button>
  </div>

  <script src="https://unpkg.com/@bookklik/senangstart-actions"></script>
</body>
</html>

Summary

PropertyPurposeExample
$refsAccess elements by reference$refs.input.focus()
$storeAccess global stores$store.user.name
$elCurrent element$el.classList.add('active')
$eventNative event object$event.target.value
$dispatchEmit custom events$dispatch('save', data)