npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

create-ayisha-app

v1.1.3

Published

Ayisha.js - Un framework JavaScript per SPA, simile a Vue/React

Readme

Ayisha.js v1.1.2

Ayisha.js is a micro JavaScript framework for building reactive, component-based user interfaces. It offers a minimalist syntax, a powerful directive system, and an extremely lightweight bundle for fast and modern web development.

Main Features

  • Virtual DOM and reactive rendering
  • 50+ directives for every use case (@if, @for, @model, @click, @when, @do, @go, @form, etc.)
  • Native components and async loading of external components
  • Built-in SPA routing with advanced navigation
  • Async fetch and state management with error handling
  • Form validation and two-way binding
  • Declarative forms with @form
  • File upload support with base64 encoding
  • Date formatting directives
  • Smart logger for directive debugging
  • Inline help system for all directives
  • Enhanced error reporting and debugging

Important Note

Ayisha.js is currently a client-side framework. Server-side rendering and hydration are not supported in the current runtime.

Ayisha.js now also includes a browser-based prerendering flow for SEO-friendly HTML delivery. This is not native SSR: the server opens the page in a real browser, waits for Ayisha and @fetch to settle, captures the rendered HTML, and sends that HTML to the client. The client then restores the original Ayisha source markup and re-mounts interactivity.

Prerendering and SEO

What it is

  • Browser-based prerendering: a Node server opens your Ayisha page in Chrome/Chromium via the DevTools Protocol, waits for the app to finish rendering, and returns the final HTML.
  • SEO-friendly first response: crawlers and users receive rendered HTML immediately.
  • Client interactivity preserved: after load, Ayisha restores the source template and rebinds routing, links, components, and state on the client.

What it is not

  • It is not native SSR.
  • It is not hydration in the React/Vue sense.
  • It currently depends on a local Chrome/Chromium instance started with remote debugging enabled.

Root scripts

The repository includes these scripts:

  • npm run prerender — prerender one or more HTML entries to files
  • npm run prerender:demo — prerender the local fetch demo
  • npm run prerender:server — start the generic prerender server
  • npm run prerender:server:test — start the prerender server against the sample project in test/

Start Chrome for prerendering

On macOS:

/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222 --user-data-dir=/tmp/ayisha-prerender

Start the test project server

npm run prerender:server:test

By default this serves the project in test/ and prerenders SPA routes through index.html.

Example routes validated in this repository

  • /categories
  • /random
  • /category-meals/Seafood
  • /search?area=Italian

CLI Prerender Scaffold

The CLI can now generate a prerender-ready project without third-party SSR dependencies.

Generate a project

node ayisha-cli/bin/create-ayisha-app.js my-app --template SPA --mode cdn --prerender

For the prerender-ready recipe demo starter used in this repository:

node ayisha-cli/bin/create-ayisha-app.js recipe-browser --template RecipeBrowser --mode cdn --prerender

For a smaller route-based starter without the recipe demo domain:

node ayisha-cli/bin/create-ayisha-app.js landing-spa --template PrerenderSPA --mode cdn --prerender

What --prerender adds

  • if you do not pass --template, the CLI now defaults to PrerenderSPA
  • copies a local ayisha.js into the generated project
  • adds <base href="/"> to the generated HTML
  • uses a local Ayisha script instead of the CDN tag
  • copies these scripts into the generated project:
    • scripts/prerender-core.cjs
    • scripts/prerender.cjs
    • scripts/prerender-server.cjs
  • adds these npm scripts to the generated package.json:
    • npm run prerender
    • npm run prerender:server

RecipeBrowser template

RecipeBrowser is a dedicated starter based on the sample app in test/.

  • available in cdn mode only
  • ships with pages and components already split into partial HTML files
  • includes route-to-state bootstrap for SPA URLs and query strings
  • is ready to be served through npm run prerender:server for SEO-friendly output

PrerenderSPA template

PrerenderSPA is the smaller generic starter for prerendered Ayisha SPAs.

  • single-file starter with no demo-specific domain logic
  • includes URL path and query-string to initial-state mapping
  • keeps @link navigation and direct route entry aligned with prerender output
  • useful as a clean base before splitting into components and pages

Run the generated prerender server

cd my-app
npm run prerender:server

The generated server defaults to http://127.0.0.1:8080 and serves prerendered HTML for the SPA entry while leaving component/page partials as raw HTML for the client runtime.

Installation

Via CDN (recommended)

<script src="https://cdn.jsdelivr.net/gh/BenJrSky/ayisha.js@main/dist/ayisha-1.1.2-min.js"></script>

Local Download

Download the file and include it in your project:

<script src="Ayisha-1.1.2.js"></script>

Or use the minified version:

<script src="Ayisha-1.1.2-min.js"></script>

Basic Example

<div>
  <init>
    title = 'Hello Ayisha!';
    count = 0;
    items = ['Apple', 'Banana', 'Orange'];
  </init>
  
  <h1>{{ title }}</h1>
  <input @model="title">
  <button @click="count++">Increment: {{ count }}</button>
  <ul>
    <li @for="item in items">{{ item }}</li>
  </ul>
</div>

  <script src="https://cdn.jsdelivr.net/gh/BenJrSky/ayisha.js@main/dist/ayisha-1.1.2-min.js"></script>

What's New in v1.1.2

Bug Fixes and Performance Improvements

  • Performance optimizations: Improved rendering performance and reduced memory usage.
  • Bug fixes: Fixed various issues with directive handling and state management.
  • Stability improvements: Enhanced error handling and fallback mechanisms.

Previous (v1.1.1)

La release precedente (v1.1.1) conteneva importanti refactor di sicurezza e centralizzazione:

Refactor e centralizzazioni

  • AYISHA_CONSTS: introdotta la costante centrale AYISHA_CONSTS per raggruppare JS_GLOBALS, TIMINGS e la regex SIMPLE_IDENTIFIER_RE.
  • Helper identificatori: aggiunte le funzioni ayisha_isSimpleIdentifier(expr) e ayisha_hasUnsafeExpressionChars(expr) per unificare i controlli ripetuti e rendere il codice più leggibile e sicuro.
  • Tempi centralizzati: tutti i "valori magici" (es. 10, 1500, 2000) sono stati sostituiti con AYISHA_CONSTS.TIMINGS.* dove appropriato.

Rimozione SSR / Hydration

  • Rimosso SSR: eliminati i metodi e i percorsi relativi a SSR e rendering stringa: renderForSEO, renderToString, _parseTemplateForSSR, _renderVNodeToString e gli helper SSR correlati.
  • Rimosso hydration: eliminati gli helper e i percorsi di hydration client-side (hydrate, _hydrateEventListeners, _hydrateInteractiveDirectives, _hydrateBindings, AyishaVDOM.createSSRInstance, AyishaVDOM.hydrate).
  • Startup unificato: l'avvio ora è sempre new AyishaVDOM(document.body).mount(); il branching su __AYISHA_HYDRATION_DATA__ è stato rimosso.
  • Opzioni/flag rimossi: tolte le opzioni di default ssr/hydration dalle options; rimosse anche le variabili interne _isSSRMode, _ssrOutput, _hydrationData.
  • Costante SSR rimossa: SSR_FETCH_WAIT rimossa da TIMINGS.

Sicurezza: centralizzazione e hardening dell'evaluator

  • ExpressionCompiler: introdotto un compilatore centralizzato per espressioni con cache separate per espressioni (exprCache), statement (stmtCache) e corpi di funzione (funcCache).
  • Cache con limite: semplice limite MAX_CACHE e pulizia automatica quando superato.
  • API pubbliche: funzioni esposte compileExpr, compileStmt, compileFunction, isSuspicious per instradare tutte le valutazioni nel compilatore.
  • Routing della compilazione: tutte le invocazioni che prima usavano new Function(...) (valutazione espressioni, init blocks, @map/@filter/@reduce, executeMultipleExpressions, ecc.) passano ora attraverso ExpressionCompiler.
  • Validator warn-mode: controllo conservativo per token sospetti (process, require, global, Function, eval, constructor) che emette console.warn (modalità non bloccante).
  • Logging e fallback: fallimenti di compilazione/esecuzione loggati con console.error; forniti fallback no-op per evitare crash a runtime.

Robustezza e performance

  • Caching: riduzione delle compilazioni ripetute migliorando le performance runtime.
  • Try/catch aggiuntivi: invocazioni dinamiche (map/filter/reduce e funzioni generate) ora avvolte da try/catch per isolare errori e prevenire interruzioni globali.
  • Fallback sicuro: in caso di errori di compilazione viene usato un fallback che evita crash dell'applicazione.

Gestione attività

  • TODO interno aggiornato: la lista TODO del progetto è stata creata/aggiornata (tramite manage_todo_list) per tracciare i passi completati e quelli successivi; le voci A/B/D sono state marcate completate internamente.

Nota di compatibilità

Questi cambiamenti sono principalmente interni e mirano a migliorare sicurezza, manutenzione e performance. Se la tua integrazione dipendeva da API SSR/hydration o da exposures interne precedenti, verifica le parti che ora sono state rimosse o centralizzate (es. chiamate dirette a AyishaVDOM.hydrate o utilizzo di flag ssr/hydration).

Previous (v1.1.1)

La release precedente (v1.1.1) conteneva importanti refactor di sicurezza e centralizzazione come descritto sopra; v1.1.2 applica correzioni di bug e miglioramenti di performance.

Complete Directive Reference

Directive Execution Order (Hierarchy)

Directives execute in this priority order:

  1. @page / @if / @not / @show / @hide — Conditional rendering
  2. @for — Loop iteration
  3. @fetch / @result / @source / @map / @filter / @reduce — Data handling
  4. @src — Component loading
  5. @form / @model / @validate / @file / @files — Form binding and validation
  6. @class / @style — Styling
  7. @click / @input / @focus / @blur / @change / @hover / @set — Events
  8. @text / @date / @dateonly / @time — Text content and formatting
  9. @key — Loop optimization
  10. @then / @finally — Post-execution
  11. @log / @state / @attr / @prev — Debug helpers

Core Directives

| Directive | Description | Example | |-----------|-------------|---------| | @if | Show element if condition is true | <div @if="isLoggedIn">Welcome!</div> | | @not | Show element if condition is false | <div @not="isLoggedIn">Please login</div> | | @show | Show/hide element (CSS display) | <div @show="menuOpen">Menu</div> | | @hide | Hide element if condition is true | <div @hide="loading">Content</div> | | @for | Loop over arrays/objects | <li @for="item in items" @key="item.id">{{item.name}}</li> | | @form | Declarative form container | <form @form @result="onSubmit">...</form> | | @model | Two-way data binding | <input @model="searchQuery"> | | @click | Handle click events | <button @click="count++">Increment</button> |

Form Container Directive

| Directive | Description | Example | |-----------|-------------|---------| | @form | Declarative form with built-in validation and submission | <form @form @result="onSubmit">...</form> |

File Upload Directives

| Directive | Description | Example | |-----------|-------------|---------| | @file | Single file upload as base64 | <input type="file" @file="avatar"> | | @files | Multiple file uploads as base64 array | <input type="file" multiple @files="gallery"> |

Date Formatting Directives

| Directive | Description | Example | |-----------|-------------|---------| | @date | Format full date and time | <span @date="createdAt">Jan 1, 2025, 10:30 AM</span> | | @dateonly | Format date only | <span @dateonly="createdAt">Jan 1, 2025</span> | | @time | Format time only | <span @time="createdAt">10:30 AM</span> |

Advanced Navigation Directives

| Directive | Description | Example | |-----------|-------------|---------| | @when | Watch condition, trigger on true transition | <span @when="_currentPage=='home'" @do="step='004'"></span> | | @do | Execute expression when @when triggers | <span @when="!isLoggedIn" @do="showLogin=true"></span> | | @go | Navigate to page when @when triggers | <span @when="error" @go="home"></span> | | @wait | Delay @do/@go execution (milliseconds) | <span @when="success" @wait="2000" @go="dashboard"></span> |

Data and API Directives

| Directive | Description | Example | |-----------|-------------|---------| | @fetch | Perform HTTP request | <div @fetch="'https://api.com/data'" @result="data"></div> | | @result | Target variable for @fetch result | <div @fetch="apiUrl" @result="users"></div> | | @error | Custom error variable for @fetch | <div @fetch="apiUrl" @result="data" @error="myError"></div> | | @source | Data source for transformations | <div @source="items" @map="item*2" @result="doubled"></div> | | @map | Transform array items | <div @source="items" @map="item => item.name"></div> | | @filter | Filter array items | <div @source="items" @filter="item.active"></div> | | @reduce | Reduce array to single value | <div @source="items" @reduce="acc+item" @initial="0"></div> |

Component and Routing

| Directive | Description | Example | |-----------|-------------|---------| | @src | Component source URL | <component @src="./components/card.html"></component> | | @link | SPA navigation link | <a @link="about">About Page</a> | | @page | Show only on specific page | <div @page="home">Home content</div> |

Form and Validation

| Directive | Description | Example | |-----------|-------------|---------| | @validate | Input validation rules (improved in 1.0.3) | <input @model="email" @validate="required,email"> | | @set | Set state values on events | <button @click="isOpen=true; count=0">Reset</button> |

Event Directives

| Directive | Description | Example | |-----------|-------------|---------| | @input | Handle input events | <input @input="validateForm()"> | | @focus | Handle focus events | <input @focus="showHelp=true"> | | @blur | Handle blur events | <input @blur="validateField()"> | | @change | Handle change events | <select @change="updateResults()"> | | @hover | Handle hover events | <div @hover="showTooltip=true"> |

Styling Directives

| Directive | Description | Example | |-----------|-------------|---------| | @class | Dynamic CSS classes | <div @class="{active: isActive, hidden: !visible}"> | | @style | Dynamic inline styles | <div @style="{color: themeColor, fontSize: size+'px'}"> | | @text | Set element text content | <span @text="userName"></span> |

Advanced Features

| Directive | Description | Example | |-----------|-------------|---------| | @switch | Switch statement for multiple conditions | <div @switch="status"> | | @case | Case option for @switch | <div @case="'loading'">Loading...</div> | | @default | Default case for @switch | <div @default>Unknown status</div> | | @key | Unique key for @for optimization | <li @for="item in items" @key="item.id"> | | @animate | Apply CSS animations | <div @animate="fadeIn"> | | @then | Execute after other directives | <div @then="console.log('rendered')"> | | @finally | Execute after everything | <div @finally="cleanup()"> |

Debug and Development

| Directive | Description | Example | |-----------|-------------|---------| | @log | Show directive debug info | <button @click="count++" @log>Debug me</button> | | @state | Show current state as JSON | <div @state></div> | | @prev | Show current and previous values | <div @prev="userName"></div> | | @attr | Show state attributes list | <div @attr></div> | | no | Disable interpolation | <no>{{this won't be processed}}</no> |

Event Variants

Most directives support event-specific variants:

  • @fetch:click — Fetch on click
  • @model:change — Bind on change event
  • @class:hover — Apply classes on hover
  • @set:input — Set values on input
  • @text:focus — Update text on focus

Practical Examples

Navigation Flow Control

<!-- Automatic redirects and guided flows -->
<span @when="!isLoggedIn" @go="login"></span>
<span @when="_currentPage=='random'" @wait="3000" @go="home"></span>
<div @when="searchResults.length > 0" @do="showMessage=true"></div>

Advanced Forms

<form @form @result="loginResult">
  <input @model="user.email" @validate="required,email">
  <input @model="user.password" @validate="required,minLength:8">
  <button type="submit">Login</button>
</form>

Dynamic Data Processing

<div @source="products" 
     @filter="item => item.price < maxPrice"
     @map="item => ({...item, discounted: item.price * 0.9})"
     @result="discountedProducts">
     
  <div @for="product in discountedProducts" @key="product.id">
    <h3>{{product.name}}</h3>
    <span class="price">{{product.discounted}}</span>
  </div>
</div>

Conditional UI with Switch

<div @switch="orderStatus">
  <div @case="'pending'" class="status-pending">
    <span>⏳ Processing your order...</span>
  </div>
  <div @case="'shipped'" class="status-shipped">
    <span>🚚 Order shipped!</span>
  </div>
  <div @case="'delivered'" class="status-delivered">
    <span>✅ Order delivered</span>
  </div>
  <div @default class="status-unknown">
    <span>❓ Unknown status</span>
  </div>
</div>

File Upload with Preview

<div>
  <input type="file" @file="profilePicture" accept="image/*">
  <div @if="profilePicture">
    <img @src="profilePicture" alt="Profile Preview" style="max-width: 200px;">
  </div>
</div>

<!-- Multiple files -->
<div>
  <input type="file" multiple @files="gallery" accept="image/*">
  <div @for="image in gallery" @key="$index">
    <img @src="image" alt="Gallery Image" style="max-width: 100px; margin: 5px;">
  </div>
</div>

Date Formatting

<div>
  <p @date="post.createdAt"></p>        <!-- "January 1, 2025, 2:30 PM" -->
  <p @dateonly="post.createdAt"></p>    <!-- "January 1, 2025" -->
  <p @time="post.createdAt"></p>        <!-- "2:30 PM" -->
</div>

Enhanced Error Handling

<div>
  <button @fetch:click="'/api/users'" @result="users" @error="userError">
    Load Users
  </button>
  
  <div @if="userError" class="error">
    Error: {{userError.error}}
  </div>
  
  <div @if="users && !userError">
    <div @for="user in users">{{user.name}}</div>
  </div>
</div>

Conditional Rendering with @not

<div @not="user.isLoggedIn">
  <h2>Please log in to continue</h2>
  <button @click="showLoginForm=true">Login</button>
</div>

<div @if="user.isLoggedIn">
  <h2>Welcome back, {{user.name}}!</h2>
</div>

Debug with Previous Values

<div>
  <input @model="searchQuery">
  <div @prev="searchQuery"></div>  <!-- Shows current and previous values -->
</div>

Full Form Example with Validation

<form @form @result="onSubmit" @error="formError">
  <input @model="user.email" @validate="required,email">
  <input @model="user.password" @validate="required,minLength:8">
  <input @model="user.age" @validate="required,min:18">
  <button type="submit">Register</button>
  <div @if="formError" class="error">{{formError}}</div>
</form>

Advanced Contact Form Example (Italiano)

<div class="comment-box" @form="comunicazione">
  <h3>Scrivici</h3>
  <div class="form-inner">
    <form method="post" action="blog-details.html">
      <div class="row clearfix">
        <div class="col-lg-6 col-md-6 col-sm-12 single-column">
          <div class="form-group">
            <label>Nome <span>*</span></label>
            <input type="text" @model="name" @validate="minLength=3">
            <label @if="_validate.name==false" class="text-danger">Nome non valido</label>
          </div>
        </div>
        <div class="col-lg-6 col-md-6 col-sm-12 single-column">
          <div class="form-group">
            <label>Telefono <span>*</span></label>
            <input type="email" @model="phone" @validate="phone">
            <label @if="_validate.phone==false" class="text-danger">Telefono non valido</label>
          </div>
        </div>
        <div class="col-lg-12 col-md-12 col-sm-12 single-column">
          <div class="form-group">
            <label>Messaggio <span>*</span></label>
            <textarea @model="message" @validate="minLength=20" @change="sent=false"></textarea>
            <label @if="_validate.message==false" class="text-danger">Scrivi almeno 20 caratteri</label>
          </div>
        </div>
        <div class="col-lg-12 col-md-12 col-sm-12 single-column">
          <div class="message-btn">
            <button class="theme-btn btn-one px-5 py-2"
              @if="_validate.comunicazione" @fetch:click="/api/content"
              @method="post" @headers="{ 'Content-Type': 'application/json'}"
              @payload="{ schemaName: 'messages', data: { name: name, phone: phone, message: message, read: false, public:false } }"
              @then="name=''; phone=''; message='';sent=true"
              @result="responseMessage">Invia</button>
            <button @not="_validate.comunicazione" class="border rounded-pill px-5 py-2">Invia</button>
            <label @show="sent">Messaggio Inviato</label>
          </div>
        </div>
      </div>
    </form>
  </div>
</div>

Advanced Contact Form Example (English)

<div class="comment-box" @form="contact">
  <h3>Contact Us</h3>
  <div class="form-inner">
    <form method="post" action="blog-details.html">
      <div class="row clearfix">
        <div class="col-lg-6 col-md-6 col-sm-12 single-column">
          <div class="form-group">
            <label>Name <span>*</span></label>
            <input type="text" @model="name" @validate="minLength=3">
            <label @if="_validate.name==false" class="text-danger">Name is not valid</label>
          </div>
        </div>
        <div class="col-lg-6 col-md-6 col-sm-12 single-column">
          <div class="form-group">
            <label>Phone <span>*</span></label>
            <input type="email" @model="phone" @validate="phone">
            <label @if="_validate.phone==false" class="text-danger">Phone is not valid</label>
          </div>
        </div>
        <div class="col-lg-12 col-md-12 col-sm-12 single-column">
          <div class="form-group">
            <label>Message <span>*</span></label>
            <textarea @model="message" @validate="minLength=20" @change="sent=false"></textarea>
            <label @if="_validate.message==false" class="text-danger">Please write at least 20 characters</label>
          </div>
        </div>
        <div class="col-lg-12 col-md-12 col-sm-12 single-column">
          <div class="message-btn">
            <button class="theme-btn btn-one px-5 py-2"
              @if="_validate.contact" @fetch:click="/api/content"
              @method="post" @headers="{ 'Content-Type': 'application/json'}"
              @payload="{ schemaName: 'messages', data: { name: name, phone: phone, message: message, read: false, public:false } }"
              @then="name=''; phone=''; message='';sent=true"
              @result="responseMessage">Send</button>
            <button @not="_validate.contact" class="border rounded-pill px-5 py-2">Send</button>
            <label @show="sent">Message Sent</label>
          </div>
        </div>
      </div>
    </form>
  </div>
</div>

Components

Define inline components:

ayisha.component('user-card', `
  <div class="card">
    <img src="{{user.avatar}}" alt="{{user.name}}">
    <h3>{{user.name}}</h3>
    <p>{{user.email}}</p>
  </div>
`);

Use components:

<component @src="/components/header.html"></component>

SPA Routing

<!-- Navigation -->
<nav>
  <a @link="home">Home</a>
  <a @link="about">About</a>
  <a @link="contact">Contact</a>
</nav>

<!-- Pages -->
<div @page="home">
  <h1>Welcome Home</h1>
</div>
<div @page="about">
  <h1>About Us</h1>
</div>
<div @page="contact">
  <component @src="/pages/contact.html"></component>
</div>

Form Validation

<input @model="email" @validate="required,email">
<input @model="password" @validate="required,minLength:8,password">
<input @model="age" @validate="required,min:18,max:100">
<input @model="website" @validate="url">
<input @model="phone" @validate="phone">

Available validation rules:

  • required — Field is required
  • email — Valid email format
  • minLength:n — Minimum length
  • maxLength:n — Maximum length
  • min:n — Minimum numeric value
  • max:n — Maximum numeric value
  • password — Strong password
  • phone — Valid phone number
  • url — Valid URL
  • regex:pattern — Custom regex pattern

API Integration

<!-- Simple fetch -->
<div @fetch="'https://api.example.com/users'" @result="users">
  <div @for="user in users" @key="user.id">
    {{user.name}}
  </div>
</div>

<!-- Fetch with error handling -->
<button @click="loading=true; error=''" 
        @fetch:click="apiUrl" 
        @result="data"
        @error="customError">
  Load Data
</button>

<div @if="loading">Loading...</div>
<div @if="customError">Error: {{customError.error}}</div>
<div @if="data && !loading && !customError">
  <!-- Success content -->
</div>

State Management

Initialize state:

<init>
  // Application state
  user = { name: '', email: '', loggedIn: false };
  products = [];
  cart = [];
  currentPage = 'home';
  
  // UI state  
  loading = false;
  error = '';
  modalOpen = false;
  
  // Settings
  theme = 'light';
  language = 'en';
</init>

Debug and Development

Add logging to any element:

<button @click="count++" @log>Debug Button</button>

Show current state:

<div @state></div>              <!-- Full state -->
<div @state="user"></div>       <!-- Specific object -->
<div @state="user.name"></div>  <!-- Specific property -->

Show previous values for debugging:

<div @prev></div>               <!-- All previous values -->
<div @prev="userName"></div>    <!-- Specific variable history -->

Performance Tips

  1. Use @key for lists: Always provide unique keys for @for loops
<li @for="item in items" @key="item.id">{{item.name}}</li>
  1. Optimize conditions: Place most likely conditions first
<div @if="isLoggedIn && user.isAdmin">Admin Panel</div>
  1. Batch state updates: Use @set for multiple updates
<button @click="loading=true; error=''; step=1">Start</button>
  1. Use @show vs @if: Use @show for frequent toggles, @if for rare conditions
<div @show="menuOpen">Menu</div>      <!-- Frequent toggle -->
<div @if="user.isAdmin">Admin</div>   <!-- Rare condition -->
  1. Use @not for cleaner inverse conditions:
<div @not="user.isAdmin">Regular user content</div>

API Reference

State Access

  • Access: {{variableName}} or {{object.property}}
  • Binding: @model="variableName"
  • Updates: @click="variableName = newValue"

File Handling

  • Single file: @file="variableName" (stores base64 string)
  • Multiple files: @files="arrayVariable" (stores array of base64 strings)

Date Formatting

  • Full format: @date="isoDateString"
  • Date only: @dateonly="isoDateString"
  • Time only: @time="isoDateString"

Migration from v1.0.2

Breaking Changes

  • @form now manages form submission and validation automatically; remove manual event handlers for forms
  • Validation logic is now stricter and more extensible; custom rules may need to be updated

New Features to Adopt

  1. Use @form for all forms to get automatic validation and error handling
  2. Use improved @validate for more robust validation
  3. Use @file and @files for file uploads
  4. Use @date, @dateonly, @time for date formatting
  5. Use @not for cleaner inverse conditions
  6. Use @prev for debugging state changes
  7. Use @error for custom fetch error handling

License

MIT License © 2025 devBen


Ayisha.js v1.1.2 - Build reactive UIs with minimal code. Fast, lightweight, and powerful.

Created with ❤️ by devBen