# Components In SUI, **every page is a component**. Any page can be embedded into another page using the `is` attribute. ## Core Concept When a page is used as a component: 1. The page's HTML becomes the component template 2. The page's CSS is automatically scoped 3. The page's TypeScript becomes the component class 4. The page's `backend.ts` provides server-side logic via `BeforeRender` ## Creating a Component A component is just a page with a single root element: **`/card/card.html`**: ```html

{{ title }}

``` **`/card/card.css`**: ```css .card { border: 1px solid #ddd; border-radius: 8px; padding: 16px; } .card h3 { margin: 0 0 12px; } ``` **`/card/card.ts`**: ```typescript function card(component: HTMLElement) { this.root = component; this.store = new __sui_store(component); this.props = new __sui_props(component); } ``` ## Using Components ### Basic Usage Use the `is` attribute to embed a page as a component: ```html

Card content goes here

``` ### With Import Alias Use `` for cleaner syntax: ```html

Content

``` ## Props Props are passed as attributes: ```html
``` Access props in the component script: ```typescript function userCard(component: HTMLElement) { this.root = component; this.props = new __sui_props(component); // Get single prop const name = this.props.Get("name"); // Get all props const allProps = this.props.List(); // { name: "John", email: "john@example.com", avatar: "...", role: "admin" } } ``` Access props in backend script: ```typescript function BeforeRender( request: Request, props: Record ): Record { const userId = props.userId; return { user: Process("models.user.Find", userId), }; } ``` ## Children and Slots ### Children Use `` to render child content: **Component (`/panel/panel.html`)**: ```html
{{ title }}
``` **Usage**: ```html

This content appears in the panel body

``` ### Named Slots Use `` for multiple content areas: **Component (`/modal/modal.html`)**: ```html ``` **Usage**: ```html

Confirmation

Are you sure you want to proceed?

``` ## Dynamic Components ### Variable Component Route ```html
``` ### Dynamic Tag ```html ``` ## Component Script ### Structure ```typescript function componentName(component: HTMLElement) { // Root element this.root = component; // Data store (data-* attributes) this.store = new __sui_store(component); // Props (passed attributes) this.props = new __sui_props(component); // State management this.state = new __sui_state(this); // Backend API this.backend = { ApiMethod: async (...args) => { /* ... */ }, }; // State watchers this.watch = { propertyName: (value, state) => { // React to state changes }, }; // Methods this.handleClick = (event, data, context) => { // Handle events }; } ``` ### Store API ```typescript // String data this.store.Get("key"); this.store.Set("key", "value"); // JSON data this.store.GetJSON("items"); this.store.SetJSON("items", [{ id: 1 }]); // Component data (from BeforeRender) this.store.GetData(); ``` ### Props API ```typescript // Get single prop const value = this.props.Get("propName"); // Get all props const props = this.props.List(); ``` ### State API ```typescript // Set state (triggers watchers) this.state.Set("count", 10); // Watch state changes this.watch = { count: (value, state) => { this.root.querySelector(".count").textContent = value; // state.stopPropagation(); // Prevent bubbling to parent }, }; ``` ## Nested Components Components can include other components: ```html
``` ## Component Backend Script **`/user-card/user-card.backend.ts`**: ```typescript function BeforeRender( request: Request, props: Record ): Record { const userId = props.userId; return { user: Process("models.user.Find", userId), permissions: Process("scripts.auth.GetPermissions", userId), }; } function ApiUpdateUser(userId: string, data: any, request: Request): any { return Process("models.user.Save", userId, data); } ``` ## CSS Scoping Component CSS is automatically scoped using namespace attributes: **Original CSS**: ```css .card { border: 1px solid #ddd; } .card h3 { color: #333; } ``` **Compiled CSS** (scoped): ```css [s:ns="ns_abc123"] .card { border: 1px solid #ddd; } [s:ns="ns_abc123"] .card h3 { color: #333; } ``` ## Important Notes 1. **Single Root Element**: Components must have exactly one root element 2. **Route as Identifier**: The page route becomes the component name (e.g., `/card` → `card()`) 3. **Scoped Styles**: CSS is automatically scoped to prevent conflicts 4. **Recursive Prevention**: SUI detects and prevents recursive component inclusion 5. **Script Naming**: Function name is derived from the route path