Views & .strux Template Engine
StruxJS includes a built-in server-side template engine (.strux) featuring layout inheritance, partial subviews, conditional logic, loops, XSS-safe escaping, form helpers, authorization guards, and Vite asset integration.
Creating Views & Layouts via CLI
StruxJS provides CLI commands for generating view templates and layout scaffolds inside resources/views/.
Generate a View Template (make:view)
Create a view template using dot notation or slash path:
npx strux make:view users.indexCreates resources/views/users/index.strux with default layout scaffolding.
Generate a Layout Template (make:layout)
Create a master layout scaffold inside resources/views/layouts/:
npx strux make:layout appCreates resources/views/layouts/app.strux.
Template Extension & Directory Location
View templates are stored inside resources/views/ using the .strux file extension.
Render templates from Controllers or Routes using dot notation:
// Renders: resources/views/users/profile.strux
return response.view("users.profile", { user });Or using the global view() helper:
import { view } from "struxjs";
return view("dashboard", { stats });Sharing Data with All Views (Global Helpers)
Occasionally, you may need to share specific data or custom helper functions across all views rendered by your application. You can do this using the TemplateEngine.share() method.
The best place to register global view helpers is within the boot method of your AppServiceProvider:
// app/Providers/AppServiceProvider.ts
import { TemplateEngine } from "struxjs";
export class AppServiceProvider {
public async boot() {
// Register a global helper function
TemplateEngine.share("formatDate", (dateStr: string) => {
const date = new Date(dateStr);
return `${date.getDate()}/${date.getMonth() + 1}/${date.getFullYear()}`;
});
// Share a global variable
TemplateEngine.share("appName", "StruxJS App");
}
}Once shared, you can access these variables or functions directly in any .strux view without explicitly passing them from your controllers:
<!-- Renders: StruxJS App -->
<h1>{{ appName }}</h1>
<!-- Calls the global helper -->
<p>Created: {{ formatDate(user.created_at) }}</p>Syntax & Output Escaping
1. Escaped Output ({{ }})
Values rendered inside double curly braces {{ }} are automatically escaped using __escapeHtml to prevent XSS (Cross-Site Scripting) attacks:
<h1>Hello, {{ user.name }}!</h1>2. Unescaped Raw Output ({!! !!})
Render unescaped HTML content using {!! !!}:
<div class="content">
{!! post.renderedContent !!}
</div>3. Server-Side Comments ({{-- --}})
Comments wrapped inside {{-- --}} are stripped during template compilation:
{{-- This is a hidden server-side comment --}}4. Raw Blocks (@verbatim)
Wrap blocks in @verbatim ... @endverbatim to output raw syntax without directive parsing (useful for Vue or Alpine.js syntax):
@verbatim
<div v-for="item in items">
{{ item.title }}
</div>
@endverbatim5. Raw Code Exec (@js)
Execute raw TypeScript / JavaScript statements:
@js
const timestamp = Date.now();
@endjs6. JSON Serialization (@json)
Serialize variables or objects directly to JSON string format:
<script>
const userData = @json(user);
</script>Control Structures & Directives
Conditionals (@if, @unless, @isset, @empty)
@if(user.role === 'admin')
<p>Admin Dashboard</p>
@elseif(user.role === 'editor')
<p>Editor Panel</p>
@else
<p>User Profile</p>
@endif@unless(user.isBanned)
<p>Welcome back!</p>
@endunless
@isset(user.avatar)
<img src="{{ user.avatar }}" alt="Avatar" />
@endisset
@empty(users)
<p>No users found.</p>
@endemptyLoops (@foreach, @forelse)
@foreach
Iterate over arrays or iterable collections:
<ul>
@foreach(users as user)
<li>{{ user.name }} (Index: {{ loop.index }}, Count: {{ loop.count }})</li>
@endforeach
</ul>Inside @foreach loops, the loop object provides iteration metadata:
loop.index: Current 0-based index.loop.iteration: Current 1-based iteration counter.loop.first: Returnstrueon the first iteration.loop.last: Returnstrueon the last iteration.loop.count: Total item count in the collection.
@forelse
Combines a loop with an @empty fallback block:
@forelse(posts as post)
<article>
<h2>{{ post.title }}</h2>
</article>
@empty
<p>No blog posts published yet.</p>
@endforelseAuthorization Guards (@auth, @guest, @role, @can)
@auth
<p>Welcome, {{ user.name }}</p>
@endauth
@guest
<a href="/login">Please Log In</a>
@endguest
@role('admin')
<button>Admin Settings</button>
@endrole
@can('edit-post')
<button>Edit Post</button>
@endcanForm Directives
@csrf
Generates a hidden HTML input containing the active request's CSRF token:
<form action="/login" method="POST">
@csrf
<!-- Generates: <input type="hidden" name="_token" value="..."> -->
</form>@method('PUT')
Spoofs HTTP methods (PUT, PATCH, DELETE) in standard HTML forms:
<form action="/users/42" method="POST">
@csrf
@method('PUT')
<!-- Generates: <input type="hidden" name="_method" value="PUT"> -->
</form>@error('field')
Renders a block when validation errors exist for the specified field key, injecting the error message variable:
<input type="text" name="email" value="{{ old('email') }}" />
@error('email')
<span class="error">{{ message }}</span>
@enderrorHTML Attribute Helpers
Conditionally output boolean HTML attributes:
<input type="checkbox" name="subscribe" @checked(user.isSubscribed) />
<option value="dark" @selected(user.theme === 'dark')>Dark Theme</option>
<button type="submit" @disabled(isProcessing)>Submit</button>
<input type="text" name="code" @readonly(isLocked) />
<input type="email" name="email" @required(isRequired) />Layout Inheritance & Partial Subviews
Master Layout (resources/views/layouts/app.strux)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>My Application</title>
@vite('resources/css/app.css', 'resources/js/app.js')
</head>
<body>
<header>
<h1>Site Header</h1>
</header>
<main>
@slot('content')
</main>
</body>
</html>Child View (resources/views/home.strux)
@extends('layouts.app')
@section('content')
<h2>Welcome to Home Page</h2>
<p>This content is injected into the master layout slot.</p>
@endsectionIncluding Subviews (@include, @includeIf)
Include smaller component templates into views using @include or @includeIf:
@include('partials.navbar')
@includeIf('partials.announcement_banner')Vite Asset Integration (@vite)
Inject compiled CSS and JavaScript assets using @vite():
@vite('resources/css/app.css', 'resources/js/app.js')- Development Mode: Connects directly to the Vite HMR hot-reload server (
http://localhost:5173). - Production Mode: Parses
public/build/.vite/manifest.jsonand outputs minified, version-hashed<link>and<script>tags.
IDE Setup & Syntax Highlighting
Since .strux template syntax is built on Blade-style directives (@if, @foreach, @extends, ), configuring syntax highlighting across IDEs requires associating .strux files with Blade or HTML syntax grammar.
1. Visual Studio Code, Antigravity IDE & Cursor
Open your IDE settings.json configuration file (or press Cmd+, / Ctrl+, and search for File Associations):
Add the following file association mapping:
{
"files.associations": {
"*.strux": "blade"
}
}If the blade language mode is not installed, associate .strux with html:
{
"files.associations": {
"*.strux": "html"
}
}Recommended Extension
Install the Laravel Blade Snippets extension in VS Code, Antigravity IDE, or Cursor to enable syntax colorization, snippet completion, and auto-formatting for .strux files.
2. JetBrains IDEs (WebStorm, PhpStorm, IntelliJ IDEA)
- Open
Settings/Preferences(Cmd+,on macOS orCtrl+Alt+Son Windows/Linux). - Navigate to Editor ➔ File Types.
- Locate Blade (or HTML) in the Recognized File Types list.
- Under File Name Patterns, click + (Add) and enter:
*.strux - Click Apply and OK.