Part 1: Scaffolding & Properties
Scaffold the FAQ component, define its inspector controls, and render a static themed accordion
In this part you'll create the com.example.faq component from nothing: an info.json that tells Elements what the component is, a properties.json that defines every inspector control the finished FAQ will need, a minimal hooks.js that turns those controls into Tailwind classes, and a static template with two hard-coded questions so you can see the styling work. The questions become real data in Part 2.
Create the Component Folder
If you don't have a Dev Pack yet, create one from Elements' Addons settings—the Quickstart walks through it with short videos, including how to install the pack and open its files in your editor.
Inside your pack's components/ folder, create a new folder named com.example.faq with a templates/ subfolder. By the end of this part it will contain four files:
com.example.faq/
├── info.json
├── properties.json
├── hooks.js
└── templates/
└── index.htmlElements watches Dev Pack folders, so every file you save below shows up in the app straight away—keep a page with the component open while you work.
info.json
The info.json file is the component's manifest. Create it with the following content:
{
"identifier": "com.example.faq",
"author": "Example Developer",
"title": "FAQ",
"group": "Interactive",
"tags": ["faq", "accordion", "questions"]
}Key by key:
identifier— the unique ID for the component, in reverse-DNS format: lowercase characters and periods, no spaces. Matching the folder name to the identifier keeps packs easy to navigate; every core component follows this convention.author— your name or company name.title— the name shown inside Elements. Keep it short; long titles get truncated in the UI.group— one of the pre-defined categories that Elements uses to group components in the picker. The category table lists Interactive as the home of "Modals, Popovers, Accordions, Carousels"—exactly where an FAQ accordion belongs. It's also the group the core Accordion and Tabs components use.tags— optional keywords that help users find the component.
properties.json
The properties.json file defines the inspector UI. We'll build it up as three groups—Content, Style, and Behavior—each rendered as its own section in the inspector. Group icons use SF Symbol names.
The Content Group
For now the content is a single heading above the questions, using a Text control:
The id is how you'll reference the value everywhere else—{{heading}} in templates, rw.props.heading in hooks. Part 2 adds the questions collection to this same group.
The Style Group
Styling controls should be theme controls wherever possible, so the component adapts to whatever theme the user picks—this is the central idea of Component Styling. Where a control returns a raw token, the format key wraps it into a finished Tailwind utility class:
What each control emits:
Accent — a Theme Color returns a
name-brightnesstoken likebrand-500; theformatturns it intotext-brand-500. It colors the question text — and, because the open/close indicator sits inside the question button, the indicator inherits it too.Item Gap — a Theme Spacing control in
singlemode returns one value from the theme's spacing scale; formatted asgap-y-{{value}}it yieldsgap-y-4, the vertical gap between FAQ items.Corner Radius — a Theme Border Radius control emits ready-made
rounded-*classes on its own, so it needs noformatkey.Question Size — a Theme Text Style control also emits finished utility classes, combining size and line height from Theme Studio.
The bare { "divider": {} } entries draw separator lines between the controls in the inspector.
The Behavior Group
Finally, the controls that will drive the accordion logic—two Switch controls and a Segmented control:
All three are marked "responsive": false so they return plain values (a boolean for each switch, the selected value string for the segmented control) instead of breakpoint-prefixed classes. That matters because we'll test them with @if and JavaScript comparisons later, and only non-responsive values work there.
These three controls do nothing yet. The Answers mode comes to life in Part 2, and the two switches drive the Alpine.js behavior in Part 3. Defining the full inspector now means the later parts only touch hooks.js and the templates.
A Minimal hooks.js
The hooks file runs before every render. The convention used throughout the core pack—see the "Composing Classes in hooks.js" section of Component Styling—is to gather the formatted class strings from rw.props, combine them with static classes in a classes object (one string per layer of markup), and hand the result to the template. Our hook does exactly that, in the same plain-array style as the simplified core Button example on that page:
A few things to note:
Properties like
itemGaparrive already formatted—gap-y-4, not4—because their controls did the work. The hook just slots them in next to static classes and drops empty entries with.filter(Boolean).rw.setRootElement()renders the component as a<div>carrying the wrapper classes.group/${id}names a Tailwind group after this instance's unique ID—every core component does this so hover and state variants never leak between two copies of the same component on a page.rw.setProps()passes theclassesobject to the template. Untouched properties such asheadingare available in templates automatically.The hooks runtime has no
requireorimport—everything here is plain JavaScript.
A Static Template
To prove the styling pipeline works before any real data exists, templates/index.html renders two hard-coded questions:
The template never sees the full class lists—each layer just references its entry in {{classes}}. The @if(heading) wrapper hides the <h2> entirely when the user clears the heading field, and because the root element is the flex-column wrapper from the hook, the heading and both items pick up the user's Item Gap automatically.
Try It Out
Drop the FAQ component onto a page. You should see the heading and two permanently-open questions, styled by your theme: brand-colored question text, surface-colored cards with rounded corners, and a gap between items.
[Screenshot: the FAQ component on the edit canvas showing the heading and two static, open questions]
Now open the inspector and play with the Style group—switch the accent to another theme color, bump the Item Gap, change the Question Size. Every change re-runs the hook and re-renders with new utility classes, without touching a template.
[Screenshot: the inspector's Style group next to the canvas, mid-adjustment]
Files So Far
The complete component at the end of Part 1—if your files match these, you're ready for Part 2.
info.json
properties.json
The three groups from above, combined into one file:
hooks.js and templates/index.html
Exactly as listed in the "A Minimal hooks.js" and "A Static Template" sections above.
Next Up
With the scaffolding, inspector, and styling pipeline in place, Part 2 replaces the hard-coded questions with a real collection—and lets individual answers become dropzones:
Related Documentation
Last updated
Was this helpful?

