Building Complex Components
Learn how real Elements components combine properties, hooks, collections, and templates — through guided tours of the open-source Core Pack.
The reference documentation tells you what each part of the Elements API does — every rw method, every directive, every property control. These guides answer the other question: how do real components combine those pieces into something you'd actually ship? Each guide dissects one or more components from the open-source Core Pack, so you can read the explanation with the shipping source open beside it.
What Makes a Component Complex?
A simple component is one template and a handful of properties. A complex component coordinates several files, each with a distinct job. Here is the real file tree of the core Tabs component (com.realmacsoftware.tabs):
com.realmacsoftware.tabs/
├── info.json # Manifest: identifier, title, group, and icon name
├── properties.config.json # Source property definitions, using shared globalControl references
├── properties.json # Generated inspector controls, built from properties.config.json
├── hooks.source.js # Source build-time logic — the file you actually edit
├── hooks.js # Generated hooks bundle that Elements runs at build time
├── icon.pdf # Component icon shown in the editor
├── paletteIcon.pdf # Smaller icon shown in the component palette
├── collections/
│ └── tabs/ # Defines the repeatable "tab" items users add in the inspector
│ ├── info.json # The collection's identifier and title
│ ├── defaults.json # The three starter tabs every new Tabs component begins with
│ └── properties.json # Inspector controls for each individual tab item
└── templates/
├── index.html # Main markup: loops the tabs and renders a dropzone per panel
├── alpine.html # Portal that registers the shared Alpine.js tabs behaviour once
└── editor-ui.css # Edit-mode-only CSS that reveals whichever panel is being editedTwo of these files you never touch directly: properties.json is generated from properties.config.json, and hooks.js is generated from hooks.source.js by the Core Pack's Build Tools. The source files stay small and readable; the generated files are what Elements loads. Complexity, in other words, isn't more code in one file — it's more files doing one job each.
The Three Runtimes You Write For
A component this size runs code in up to three different places, and keeping them straight is the single most useful mental model in these guides.
Build-time JavaScript (hooks.js). This code runs inside Elements while the page is generated — never in the browser. There is no require or import; everything happens through the rw object: read the user's settings from rw.props, compute derived values, and pass results to your templates with rw.setProps. If a value can be decided before the page is published, decide it here.
Browser JavaScript. Anything interactive — switching tabs, opening modals, animating on scroll — ships to the visitor's browser through your templates, usually via a portal. The Core Pack standardises on Alpine.js: each component registers its behaviour once in a bodyEnd portal, then binds it declaratively in the markup.
Server-side PHP (optional). A few components do work at request time, after publishing. The core Table component's main template is index.php, letting the published page process data on the server each time it's requested. Most components never need this runtime, but when you do, Elements treats .php templates as first-class citizens.
Guide Map
Start with the tutorial if you're building your first non-trivial component, or jump straight to the guide that matches the problem in front of you.
A four-part, end-to-end walkthrough from empty folder to finished component
Built from scratch
Registering shared Alpine behaviour via portals and binding state in your markup
Accordion, Tabs, Content Slider
Rendering overlay markup outside your component and wiring open/close triggers
Modal, Modal Close
Pairing user-editable collections with @each loops and per-item dropzones
Tabs, Table
Building families of components that discover and talk to each other
Filter, Filter Tags, Modal, Reveal
Using @if(edit), editor-only CSS, and editor properties to make editing pleasant
Table, Tabs, Gallery
Bundling a third-party library and initialising it safely with portals
Reveal, Gallery
Resource properties, responsive values, and media that adapts across breakpoints
Image, Text Wrap, Container
A worked architecture for inputs, validation, and submission handling
Generic worked example
Walking the page tree and rendering nested menus with recursive includes
Nav Tree, Menu
Related Documentation
Last updated
Was this helpful?

