# **Chapter 5: The FrontFile System - HTML with Superpowers**
## **5.1 The Philosophy of Pure HTML Templates**
SartajPHP's FrontFile system represents a radical departure from traditional PHP templating engines. Instead of inventing a new template language or forcing developers to learn special syntax, SartajPHP embraces **100% valid HTML** as its template foundation.
### **5.1.1 The Problem with Traditional Templating**
Consider these popular templating approaches:
**PHP Mixed with HTML (WordPress-style):**
```php
<div class="post">
<h2><?php echo htmlspecialchars($post->title); ?></h2>
<div class="content"><?php echo $post->content; ?></div>
<?php if ($user->isAdmin()): ?>
<a href="/edit/<?php echo $post->id; ?>">Edit</a>
<?php endif; ?>
</div>
```
**Custom Template Languages (Blade/Laravel):**
```blade
<div class="post">
<h2>{{ $post->title }}</h2>
<div class="content">{!! $post->content !!}</div>
@can('edit', $post)
<a href="{{ route('posts.edit', $post) }}">Edit</a>
@endcan
</div>
```
**Both approaches have issues:**
- **PHP-in-HTML** mixes logic with presentation, creating security risks
- **Custom languages** require learning new syntax and break HTML validation
- **Both** make collaboration with designers difficult
- **Both** create vendor lock-in
### **5.1.2 The SartajPHP Solution: HTML-First Design**
SartajPHP FrontFiles are **plain HTML files** that can be opened in any browser or editor.
SartajPHP divide designing task into Front File + Master File + Front Places. Master File
hold header and footer which design is same for whole project. The other SartajPHP Generated
Code is injected through Front Places. like Front File output show with
`SphpBase::getAppOutput()` . So we can't use html and body tag in Front File.
Here is Sample Front File Code:
```html
<!-- blog_post.front - This is 100% valid HTML -->
<article class="post">
<h2>Blog Post Title</h2>
<div class="content">
<p>This is the post content.</p>
</div>
<div class="actions">
<a href="#edit">Edit</a>
<a href="#delete">Delete</a>
</div>
</article>
```
This HTML file can be:
- **Designed** by UI/UX designers using standard tools
- **Prototyped** and tested in browsers without PHP
- **Version controlled** as plain text
- **Validated** with HTML validators
- **Processed** by build tools (minifiers, preprocessors)
**Only when needed**, developers add special attributes to enable server-side behavior:
```html
<article class="post" runas="holder" sphp-comp="postComponent">
<h2 runas="holder" sphp-app-prop="title"></h2>
<div class="content" runas="holder" sphp-app-prop="content"></div>
<div class="actions" runat="server" fur-setAuth="ADMIN">
<a href="##{getEventURL('edit', $postId)}#">Edit</a>
<a href="##{getEventURL('delete', $postId)}#">Delete</a>
</div>
</article>
```
## **5.2 FrontFile Anatomy and Structure**
### **5.2.1 File Naming and Location Conventions**
SartajPHP follows consistent naming patterns:
```
apps/ # Application directory
├── uumyappGate.php # Application class
└── fronts/ # FrontFiles directory
├── myapp_main.front # Main layout (convention: appname_main.front)
├── myapp_detail.front # Detail view
├── myapp_form.front # Form view
└── myapp_admin.front # Admin interface
```
**Best Practices:**
- Use descriptive names: `user_profile.front`, `product_list.front`, `checkout_summary.front`
- Group related files: `admin_users.front`, `admin_products.front`, `admin_settings.front`
- Keep FrontFiles small and focused (single responsibility)
### **5.2.2 The Three Processing Phases**
When a FrontFile is loaded, it goes through three distinct phases:
#### **Phase 1: Parsing**
The raw HTML is parsed into a DOM-like structure:
```
HTML Text → Parser → NodeTag Tree
```
Each HTML element becomes a `NodeTag` object with properties:
- `tagName` (div, span, input, etc.)
- `attributes` (class, id, style, etc.)
- `parentNode` (parent element)
- `childNodes` (array of child elements)
#### **Phase 2: Component Creation**
Tags with `runat="server"` are detected and corresponding Component objects are created:
```html
<!-- Before parsing: -->
<input type="text" id="username" runat="server">
<!-- After parsing: -->
NodeTag {
tagName: "input",
attributes: {type: "text", id: "username", runat: "server"},
component: TextFieldComponent {id: "username"}
}
```
#### **Phase 3: Attribute Processing**
Special attributes are processed according to their type:
- `runas` attributes transform rendering behavior, can't use with `runat`
- `runcb` attributes execute code blocks
- `*` All attributes can use as data for Components
- `fun-*` Fusion attributes can call methods of Components and pass data ",|" as separator
- Expression tags (`##{ }#`) are evaluated but not all PHP syntax supported
### **5.2.3 Minimal FrontFile Example**
We don't need html and body tags and jQuery and bootstrap because that all are provided
by Master File and project wide. But other custom css and js that is only need for this
Front File we can add in Front File.
Here's a complete, working FrontFile:
```html
<!-- apps/fronts/welcome_main.front -->
<title id="title1" runat="server">Welcome to Our Site</title>
<!-- custom css file -->
<link runas="filelink" renderonce="true"
href="myrespath/css/style1.css">
<!-- custom JavaScript -->
<script runas="filelink" renderonce="true"
src="myrespath/js/chart.js"></script>
<div class="container">
<h1>##{$siteName}#</h1>
<!-- Dynamic content from parentapp property via holder -->
<div runas="holder" sphp-app-prop="welcomeMessage"></div>
<!-- Interactive form submit via AJAX -->
<form id="contactForm" runat="server" fun-setAJAX="">
<input id="txtName" runat="server" type="text"
placeholder="Your Name"
fui-setRequired=""
fui-setForm="contactForm">
<input id="txtEmail" runat="server" type="email"
placeholder="Your Email"
fui-setRequired=""
fui-setEmail=""
fui-setForm="contactForm">
<button type="submit">Send Message</button>
</form>
<!-- Conditional display, Tag Remove from output if user isn't admin -->
<div id="adminPanel" runat="server" fur-setAuth="ADMIN">
<h3>Admin Controls</h3>
<a href="##{getGateURL('admin')}#">Dashboard</a>
</div>
</div>
```
## **5.3 Runtime Attributes: Controlling Behavior**
Runtime attributes are the key to SartajPHP's power. They transform ordinary HTML tags into dynamic, server-aware elements.
### **5.3.1 The Three Runtime Attributes**
| Attribute | Purpose | Creates Component? |
|-----------|---------|-------------------|
| `runat="server"` | Makes tag a server-side Component | Yes |
| `runas="value"` | Changes rendering behavior | No |
| `runcb="true"` | Executes code blocks | No |
### **5.3.2 runat="server" - Server-Side Components**
The `runat="server"` attribute is the most powerful runtime attribute. It tells SartajPHP: "Treat this HTML element as a server-side Component." SartajPHP identify Tag and find relative inbuilt Component or otherwise it will choose
Tag Component or you can give path of your own Component File with `path` attribute.
**Basic Usage:**
```html
<!-- Becomes a TextField Component -->
<input type="text" id="username" runat="server">
<!-- Becomes an Alert Component -->
<alert id="app" runat="server"></alert>
<!-- Becomes a generic Tag Component -->
<span id="status" runat="server">Loading...</span>
<!-- Becomes a Pagination Component -->
<div id="showall" runat="server" path="uikit/data/Pagination.php"
dtable="profile"
fun-setFieldNames="profile_name,permission_id"
fun-setAJAX="" >
<div runas="holder" dfield="profile_name" sphp-comp="showall"></div>
</div>
<div id="pagebar" runas="holder" sphp-comp="showall" sphp-comp-prop="page_links"></div>
```
**What happens when you add `runat="server"`:**
1. A Component object is instantiated
2. The Component binds to the NodeTag
3. Fusion attributes become active
4. The Component participates in lifecycle events
5. Server-side validation becomes possible
6. Database binding can be configured
### **5.3.3 runas - Rendering Transformations**
The `runas` attribute changes how a tag is rendered without creating a Component.
**Common `runas` values:**
| Value | Purpose | Example |
|-------|---------|---------|
| `filelink` | Manage CSS/JS resources | `<link runas="filelink" href="style.css">` |
| `holder` | Dynamic content placeholder | `<div runas="holder" sphp-app-prop="content">` |
| `jsfunction` | Generate JavaScript functions | `<script runas="jsfunction">` |
| Custom tag | Semantic HTML mapping | `<card runas="div">` |
**Examples:**
```html
<!-- Resource management -->
<link runas="filelink" renderonce="true" href="css/app.css">
<script runas="filelink" renderonce="true" src="js/app.js">
<!-- Dynamic content -->
<div runas="holder" sphp-comp="userProfile" sphp-comp-prop="name"></div>
<!-- Semantic tags -->
<card runas="div" class="card">
<card-header runas="div" class="card-header">Title</card-header>
<card-body runas="div" class="card-body">Content</card-body>
</card>
```
### **5.3.4 runcb="true" - Code Block Execution**
Code blocks allow reusable layout transformations without creating Components.
**Basic Usage:**
```html
<!-- Apply border code block -->
<div runcb="true" sphp-cb-border="2,primary">
Content with border
</div>
<!-- Apply multiple code blocks -->
<article runcb="true" title="My Title"
sphp-cb-card="Header,|Footer"
sphp-cb-shadow="lg"
sphp-cb-padding="3">
Blog post content
</article>
```
**Code blocks are defined in `sphpcodeblock.php`:**
```php
final class SphpCodeBlock{
/**
* Add Code Block for FrontFile. use runcb="true" and sphp-cb-blockName on tag
* @param string $name Name of code block
* @param function $callback function($element,$args,$lstOther_CB){}
* $element= \Sphp\tools\NodeTag object,
* $args=list of arguments as indexed array,
* $lstOther_CB=List of other Code Blocks apply on this element
* @param array $para add css,html for simple code block
* Values can pass as associative array:-
* class = CSS class Attribute
* pclass = parent tag css classes
* pretag = pre tag html
* posttag = post tag html
* innerpretag = tag start inner html
* innerposttag = tag end inner html
* documentation = Help details about code block, also display in VS Code and other editors.
*/
public static function addCodeBlock($name,$callback=null,$para=[]){}
}
SphpCodeBlock::addCodeBlock('card', function($element, $args, $lstOther_CB) {
$element->wrapTag('<div class="card"></div>');
$element->wrapInnerTags('<div class="card-body"></div>');
if (!empty($args[0])) {
$element->setPreTag('<div class="card-header">' . $args[0] . '</div>');
}
if (!empty($args[1])) {
$element->setPostTag('<div class="card-footer">' . $args[1] . '</div>');
}
});
```
## **5.4 Helper Attributes: Providing Context**
Helper attributes work alongside runtime attributes to provide additional information.
### **5.4.1 Helper Attributes for runat="server"**
When a tag has `runat="server"`, these helper attributes configure the Component:
| Attribute | Purpose | Example |
|-----------|---------|---------|
| `id` | Component identifier (required) | `id="username"` |
| `path` | Custom Component class path | `path="components/CustomInput.php"` |
| `dtable` | Database table binding | `dtable="users"` |
| `dfield` | Database field binding | `dfield="email_address"` |
| `on-init` | Lifecycle event hook | `on-init="true"` |
**Example with helper attributes:**
```html
<input id="userEmail"
runat="server"
type="email"
path="components/EmailValidator.php"
dtable="subscribers"
dfield="email"
on-init="true"
fui-setRequired=""
fui-setEmail="">
```
### **5.4.2 Helper Attributes for runas="holder"**
Holder tags use these helpers to determine content source:
| Attribute | Purpose | Example |
|-----------|---------|---------|
| `sphp-comp` | Source Component | `sphp-comp="userProfile"` |
| `sphp-comp-prop` | Property name | `sphp-comp-prop="displayName"` |
| Component-specific | Field mapping | `dfield="title"` (for Pagination) |
**Holder resolution logic:**
```html
<!-- Read from Component property -->
<div runas="holder" sphp-comp="user" sphp-comp-prop="name"></div>
<!-- Get return from Component method -->
<div runas="holder" sphp-comp="user" sphp-comp-fun="getHTMLID"></div>
<!-- Read from Gate property -->
<div runas="holder" sphp-app-prop="pageTitle"></div>
<!-- Get return from Parent Gate method -->
<div runas="holder" sphp-app-fun="getBlogs"></div>
<!-- Trigger Component onholder event -->
<div runas="holder" sphp-comp="pagination"></div>
<!-- Trigger Gate onholder event -->
<div runas="holder"></div>
```
### **5.4.3 The renderonce Attribute**
The `renderonce="true"` attribute controls browser output delivery:
```html
<!-- Sent to browser only once (first page load) -->
<script runas="filelink" renderonce="true" src="js/library.js"></script>
<link runas="filelink" renderonce="true" href="css/global.css">
<!-- Sent on every request (default behavior) -->
<script runas="filelink" renderonce="false" src="js/dynamic.js"></script>
<!-- Sent to browser only once (first page load) -->
<script runas="jscode" renderonce="true">
console.log("This will not send on AJAX requests");
</script>
```
**When to use `renderonce`:**
- ✅ Global JavaScript libraries (jQuery, Bootstrap)
- ✅ Framework initialization code
- ✅ CSS files that don't change
- ✅ One-time analytics scripts
**When NOT to use `renderonce`:**
- ❌ Dynamic content that changes per request
- ❌ User-specific JavaScript
- ❌ AJAX response content
- ❌ Real-time updates
## **5.5 Expression Tags: Dynamic Content in HTML**
Expression tags provide a safe way to embed dynamic content without PHP.
### **5.5.1 Expression Tag Syntax**
```html
<!-- Output expression (auto-escaped) -->
<p>Welcome, ##{$userName}#!</p>
<!-- Silent execution (no output) -->
#{ $pageTitle = "Home Page"; }#
<!-- Raw HTML output (use with caution) -->
<div>##{raw:$htmlContent}#</div>
<!-- JSON output -->
<script>
var data = ##{json:$dataArray}#;
</script>
```
### **5.5.2 Available Variables in Expression Tags**
Expression tags have access to a limited scope:
```html
<!-- Gate properties -->
<p>##{$parentgate->siteName}#</p>
<!-- FrontFile properties -->
<p>##{$frontobj->getFilePath()}#</p>
<!-- Framework settings -->
<p>##{$sphp_settings->getBase_url()}#</p>
<!-- Metadata -->
<p>##{$metadata->get('description')}#</p>
<!-- NOT accessible: -->
<!-- ❌ $this (Gate instance) -->
<!-- ❌ Components directly -->
<!-- ❌ Superglobals ($_GET, $_POST) -->
<!-- ❌ Random PHP functions -->
```
### **5.5.3 Safe Expression Patterns**
**Good patterns:**
```html
<!-- Simple output -->
<h1>##{$pageTitle}#</h1>
<!-- URL generation -->
<a href="##{getGateURL('products')}#">Products</a>
<!-- Conditional classes -->
<div class="alert ##{getCheckErr() ? 'alert-danger' : 'alert-success'}#">
Message
</div>
<!-- ❌ no support any type of Loop, Use Loop Component or Holder -->
#{ $counter = 0; }#
<div class="items">
##{foreach:$items as $item}#
<div class="item">##{$item->name}#</div>
##{endforeach}#
</div>
```
**Avoid complex logic in expressions:**
```html
<!-- ❌ Too complex, not work -->
#{
$result = [];
foreach ($data as $item) {
if ($item->active) {
$result[] = processItem($item);
}
}
$output = implode(', ', $result);
}#
<p>##{$output}#</p>
<!-- ✅ Move to App, use holder -->
<div runas="holder" sphp-app-fun="processedData"></div>
```
## **5.6 Special Tags and Their Behavior**
### **5.6.1 `<title>` Tag Handling**
The `<title>` tag is special in SartajPHP:
```html
<!-- Regular HTML title -->
<title>My Page</title>
<!-- Dynamic title via Component -->
<title id="pageTitle" runat="server">Default Title</title>
<!-- In App: -->
public function page_new() {
$this->frtMain->getComponent("pageTitle")
->fu_setValue("Welcome to " . $this->siteName);
}
```
### **5.6.2 `<link>` and `<script>` Tags**
These tags are managed by the framework when using `runas="filelink"`:
```html
<!-- Regular HTML (framework ignores) -->
<link rel="stylesheet" href="style.css">
<script src="app.js"></script>
<!-- Framework-managed -->
<link runas="filelink" href="slibrespath/css/bootstrap.css">
<script runas="filelink" src="slibrespath/js/jquery.js"></script>
<!-- What framework does: -->
<!-- 1. Collects all filelink resources -->
<!-- 2. Deduplicates (same file loaded once) -->
<!-- 3. CSS placed in <head> -->
<!-- 4. JS placed before </body> -->
<!-- 5. Order preserved -->
```
### **5.6.3 `<form>` Tag Enhancements**
Forms gain superpowers with `runat="server"`:
```html
<!-- Regular form -->
<form action="/submit" method="post">
<input type="text" name="username">
</form>
<!-- Enhanced SartajPHP form -->
<form id="userForm" runat="server" fun-setAJAX="">
<input id="username" runat="server" type="text"
fui-setRequired=""
fui-setForm="userForm">
</form>
<!-- Benefits: -->
<!-- ✅ Automatic validation -->
<!-- ✅ AJAX submission -->
<!-- ✅ Error display -->
<!-- ✅ Database binding -->
<!-- ✅ Security protection -->
```
## **5.7 Building Reusable Layouts**
### **5.7.1 Master-Detail Pattern**
**Master layout (`masters/default/master.php`):**
```php
<?php
addFrontPlace("menu", __DIR__ . "/menu_header.php", "left");
runFrontPlace("menu", "left");
?><!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Get Global Generated Header HTML and Add global css, js Libraries -->
<?php
// add bootstrap css Framework
SphpBase::SphpJsM()::addBootStrap();
// print SartajPHP Header Generated Output
echo SphpBase::sphp_api()->getHeaderHTML();
?>
</head>
<body>
<header>
<?php
// print Menu Front Place output
renderFrontPlace("menu", "left");
?>
</header>
<main>
<?php
// print Front File output From App
SphpBase::getAppOutput();
?>
</main>
<footer>
<p>© <?php echo date('Y'); ?> My Company</p>
</footer>
<!-- Global Generated Footer HTML Code -->
<?php
// print SartajPHP Footer Generated Output
echo SphpBase::sphp_api()->getFooterHTML();
// print all errors for debug purposes
echo SphpBase::sphp_api()->traceError(true) . SphpBase::sphp_api()->traceErrorInner(true);
?>
</body>
</html>
```
**Content FrontFile (`apps/fronts/page_main.front`):**
```html
<div class="container">
<h1>##{$pageTitle}#</h1>
<div class="content">
<!-- Page-specific content here -->
<div runas="holder" sphp-app-prop="mainContent"></div>
</div>
</div>
```
### **5.7.2 Component-Based Layouts**
Build layouts from reusable Components:
```html
<!-- layout_sidebar.front -->
<div class="container-fluid">
<div class="row">
<!-- Sidebar Component -->
<div id="sidebar" runat="server"
path="components/Layout/Sidebar.php"
fun-setMenuItems="dashboard,profile,settings">
</div>
<!-- Main content area -->
<div class="col-md-9">
<div runas="holder" sphp-app-prop="content"></div>
</div>
</div>
</div>
```
### **5.7.3 Template Inheritance with Includes**
Use the Include Component for template composition:
```html
<!-- main_layout.front -->
<div class="app">
<!-- Include header -->
<include id="header" runat="server"
fui-setFrontFile="fronts/header.front">
</include>
<!-- Dynamic content -->
<main>
<div runas="holder" sphp-app-prop="pageContent"></div>
</main>
<!-- Include footer -->
<include id="footer" runat="server"
fui-setFrontFile="fronts/footer.front">
</include>
</div>
```
## **5.8 Practical FrontFile Examples**
### **5.8.1 User Registration Form**
```html
<!-- apps/fronts/register_main.front -->
<div class="container mt-5">
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card">
<div class="card-header">
<h4 class="mb-0">Create Account</h4>
</div>
<div class="card-body">
<!-- Error display of All types -->
<alert id="formErrors" runat="server" fun-setShowAll=""></alert>
<!-- Registration form -->
<form id="registerForm" runat="server" fun-setAJAX="">
<div class="mb-3">
<label class="form-label">Full Name</label>
<input id="txtFullName" runat="server"
type="text"
class="form-control"
placeholder="John Doe"
fui-setForm="registerForm"
fui-setRequired=""
fui-setMinLen="2"
fui-setMaxLen="100">
</div>
<div class="mb-3">
<label class="form-label">Email Address</label>
<input id="txtEmail" runat="server"
type="email"
class="form-control"
placeholder="john@example.com"
fui-setForm="registerForm"
fui-setRequired=""
fui-setEmail="">
</div>
<div class="mb-3">
<label class="form-label">Password</label>
<input id="txtPassword" runat="server"
type="password"
class="form-control"
placeholder="Minimum 8 characters"
fui-setForm="registerForm"
fui-setRequired=""
fui-setMinLen="8"
fur-setPassword="">
</div>
<div class="mb-3">
<label class="form-label">Confirm Password</label>
<input id="txtConfirm" runat="server"
type="password"
class="form-control"
placeholder="Re-enter password"
fui-setForm="registerForm"
fui-setRequired=""
fui-setMatch="txtPassword">
</div>
<div class="mb-3 form-check">
<input id="chkTerms" runat="server"
type="checkbox"
class="form-check-input"
fui-setForm="registerForm"
fui-setRequired="">
<label class="form-check-label">
I agree to the
<a href="##{getGateURL('terms')}#">Terms of Service</a>
</label>
</div>
<div class="d-grid">
<button type="submit" class="btn btn-primary btn-lg">
Create Account
</button>
</div>
<div class="text-center mt-3">
<small class="text-muted">
Already have an account?
<a href="##{getGateURL('login')}#">Sign In</a>
</small>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
```
### **5.8.2 Product Listing Page**
```html
<!-- apps/fronts/products_main.front -->
<div class="container">
<!-- Page header -->
<div class="row mb-4">
<div class="col">
<h1>Our Products</h1>
<p class="lead">##{$productCount}# amazing products</p>
</div>
<div class="col-auto">
<a href="##{getGateURL('cart')}#" class="btn btn-outline-primary">
View Cart (<span id="cartCount">0</span>)
</a>
</div>
</div>
<!-- Filters -->
<div class="row mb-4">
<div class="col-md-3">
<select id="sltCategory" runat="server"
class="form-select"
on-change="true">
<option value="">All Categories</option>
<option value="electronics">Electronics</option>
<option value="clothing">Clothing</option>
<option value="books">Books</option>
</select>
</div>
<div class="col-md-3">
<select id="sltSort" runat="server"
class="form-select"
on-change="true">
<option value="newest">Newest First</option>
<option value="price_low">Price: Low to High</option>
<option value="price_high">Price: High to Low</option>
<option value="rating">Highest Rated</option>
</select>
</div>
<div class="col-md-6">
<div class="input-group">
<input id="txtSearch" runat="server"
type="text"
class="form-control"
placeholder="Search products..."
fun-submitAjax="keyup">
<button class="btn btn-outline-secondary" type="button">
<i class="bi bi-search"></i>
</button>
</div>
</div>
</div>
<!-- Product grid with Pagination -->
<div id="productGrid" runat="server"
path="uikit/data/Pagination.php"
fun-setPerPageRows="12" dtable="products"
fun-setFieldNames="name,description,price">
<!-- Template for each product -->
<div class="col">
<div class="card product-card h-100">
<img src="##{$productGrid->getRow('imageUrl')}#"
class="card-img-top"
alt="##{$productGrid->getRow('name')}#">
<div class="card-body">
<h5 class="card-title">##{$productGrid->getRow('name')}#</h5>
<p class="card-text">##{$productGrid->getRow('description')}#</p>
<div class="d-flex justify-content-between align-items-center">
<span class="h5 mb-0">$##{$productGrid->getRow('price')}#</span>
<button class="btn btn-primary btn-sm add-to-cart"
data-product-id="##{$productGrid->getRow('id')}#">
Add to Cart
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Shopping cart script -->
<script runas="jsfunctioncode" function="ready">
$(document).on('click', '.add-to-cart', function() {
var productId = $(this).data('product-id');
getAJAX('cart', 'add', {product_id: productId}, function(response) {
// Update cart count
$('#cartCount').text(response.cart_count);
// Show notification
alert('Product added to cart!');
});
});
</script>
```
### **5.8.3 Admin Dashboard**
```html
<!-- apps/fronts/admin_main.front -->
<div class="container-fluid">
<div class="row">
<!-- Admin sidebar -->
<nav id="adminNav" runat="server"
class="col-md-3 col-lg-2 d-md-block bg-light sidebar collapse">
<div class="position-sticky pt-3">
<h6 class="sidebar-heading px-3 mt-4 mb-1 text-muted">
<span>Administration</span>
</h6>
<ul class="nav flex-column">
<li class="nav-item">
<a class="nav-link active" href="##{getGateURL('admin')}#">
<i class="bi bi-speedometer2"></i>
Dashboard
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="##{getEventURL('users', '', 'admin')}#">
<i class="bi bi-people"></i>
Users
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="##{getEventURL('products', '', 'admin')}#">
<i class="bi bi-box"></i>
Products
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="##{getEventURL('orders', '', 'admin')}#">
<i class="bi bi-receipt"></i>
Orders
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="##{getEventURL('settings', '', 'admin')}#">
<i class="bi bi-gear"></i>
Settings
</a>
</li>
</ul>
</div>
</nav>
<!-- Main content -->
<main class="col-md-9 ms-sm-auto col-lg-10 px-md-4">
<!-- Page header -->
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap
align-items-center pt-3 pb-2 mb-3 border-bottom">
<h1 class="h2">Dashboard</h1>
<div class="btn-toolbar mb-2 mb-md-0">
<div class="btn-group me-2">
<button type="button" class="btn btn-sm btn-outline-secondary">
Export
</button>
</div>
</div>
</div>
<!-- Stats cards -->
<div class="row">
<div class="col-md-3">
<div class="card text-white bg-primary mb-3">
<div class="card-body">
<h5 class="card-title">Total Users</h5>
<p class="card-text display-4">##{$stats['userCount']}#</p>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-white bg-success mb-3">
<div class="card-body">
<h5 class="card-title">Total Orders</h5>
<p class="card-text display-4">##{$stats['orderCount']}#</p>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-white bg-warning mb-3">
<div class="card-body">
<h5 class="card-title">Revenue</h5>
<p class="card-text display-4">$##{$stats['revenue']}#</p>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-white bg-info mb-3">
<div class="card-body">
<h5 class="card-title">Active Products</h5>
<p class="card-text display-4">##{$stats['productCount']}#</p>
</div>
</div>
</div>
</div>
<!-- Recent activity -->
<div class="row mt-4">
<div class="col-12">
<h4>Recent Activity</h4>
<div class="table-responsive">
<table class="table table-striped table-sm">
<thead>
<tr>
<th>Time</th>
<th>User</th>
<th>Action</th>
<th>Details</th>
</tr>
</thead>
<tbody>
<div id="div1" runat="server" path="slibpath/comp/server/ForEachLoop.php" fun-setObject="recentActivity">
<tr>
<td>##{$div1->getItem('time')}#</td>
<td>##{$div1->getItem('user')}#</td>
<td>##{$div1->getItem('action')}#</td>
<td>##{$div1->getItem('details')}#</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</main>
</div>
</div>
<!-- Admin-specific JavaScript -->
<script runas="jsfunctioncode" function="ready">
// Initialize dashboard charts
var ctx = document.getElementById('revenueChart').getContext('2d');
var chart = new Chart(ctx, {
type: 'line',
data: ##{json:$revenueData}#,
options: {
responsive: true,
plugins: {
legend: {
position: 'top',
},
title: {
display: true,
text: 'Revenue Trend'
}
}
}
});
</script>
```
## **5.9 Best Practices for FrontFile Development**
### **5.9.1 Organization Guidelines**
1. **Keep FrontFiles focused**: One FrontFile per "view" or "screen"
2. **Use consistent naming**: `entity_action.front` (e.g., `user_edit.front`, `product_list.front`)
3. **Group related files**: All admin FrontFiles in `fronts/admin/` directory
4. **Separate layout from content**: Use master templates for common structure
### **5.9.2 Performance Optimization**
```html
<!-- ❌ Inefficient: Loading on every request -->
<script src="heavy-library.js"></script>
<!-- ✅ Efficient: Framework manages loading -->
<script runas="filelink" renderonce="true" src="heavy-library.js"></script>
<!-- ❌ Inefficient: Complex logic in expression tags -->
#{
$result = complexCalculation();
foreach ($data as $item) {
// more processing
}
}#
<div>##{$result}#</div>
<!-- ✅ Efficient: Move to App, use holder -->
<div runas="holder" sphp-app-fun="calculatedResult"></div>
```
### **5.9.3 Security Considerations**
```html
<!-- ✅ Safe: Auto-escaped -->
<div>##{$userContent}#</div>
<!-- ✅ Explicit raw output (trusted content only) -->
<div>##{raw:$trustedHtml}#</div>
<!-- ❌ Insecure: Direct PHP access not allowed -->
<div><?php echo $_GET['param']; ?></div>
<!-- ✅ Secure: Framework-managed access -->
<div>##{$parentgate->safeParam}#</div>
```
### **5.9.4 Maintainability Tips**
1. **Comment complex sections**: Use HTML comments for documentation
2. **Use semantic class names**: `.user-profile-card` not `.div3`
3. **Keep expression tags simple**: Move complex logic to Gate layer
4. **Test FrontFiles standalone**: They should render as valid HTML without PHP
## **5.10 Common Pitfalls and Solutions**
### **5.10.1 "My runat='server' Component Isn't Working"**
**Problem:** Component doesn't behave as expected.
**Solution checklist:**
1. Verify `id` attribute is present and unique
2. Check that Component class exists and is loadable
3. Ensure no JavaScript errors are interfering
4. Clear cache: `rm -rf cache/*`
5. Check browser console for framework errors
### **5.10.2 "Expression Tags Not Evaluating"**
**Problem:** `##{ }#` tags show as literal text.
**Solutions:**
1. Ensure you're using `##{ }#` not `{{ }}` or other syntax
2. Check that variable exists in expression scope and in evaluation priority sequence
3. Verify no syntax errors in expression
4. Make sure FrontFile has `.front` extension
### **5.10.3 "CSS/JS Files Not Loading"**
**Problem:** Resources with `runas="filelink"` don't appear.
**Solutions:**
1. Check paths are correct (use `slibrespath/` for framework resources)
2. Ensure files exist at specified location
3. Verify no permission issues
4. Check browser network tab for 404 errors
## **5.11 Chapter Summary**
The FrontFile system is SartajPHP's secret weapon for productive, maintainable web development:
1. **Pure HTML Foundation**: Start with valid HTML, enhance as needed
2. **Runtime Attributes**: Add server-side behavior with `runat`, `runas`, `runcb`
3. **Safe Expression Tags**: Embed dynamic content without security risks
4. **Component Integration**: Seamlessly connect HTML with server logic
5. **Framework Management**: Automatic resource loading, caching, optimization
Key principles to remember:
- FrontFiles are **designer-friendly** - they work as pure HTML
- Runtime attributes are **optional** - add them only when needed
- Expression tags are **restricted** - for safety and clarity
- The framework **manages complexity** - focus on your application logic
With FrontFiles, you get the best of both worlds: the simplicity of plain HTML with the power of a full-stack framework. In the next chapter, we'll dive deeper into Components - the server-side building blocks that bring FrontFiles to life.
---
*Next: Chapter 6 explores Components in depth - how to create, configure, and leverage these powerful server-side UI building blocks.*