Click a contact in Post 3's grid or Post 4's table, and you'd expect a detail screen showing that one person in full. This is the simplest kind of block on the platform, precisely because there's no repetition to manage — one query, one row, values available wherever the block needs them.
No dynamiclist, no row template — a detail block is just a container with its own SQL:
<block> <!-- Block-level SQL first: its columns are tokens for everything below --> <sql> <query name="contact_detail"><![CDATA[ SELECT c.contact_name, c.job_title, c.department, c.email, c.phone, UPPER(LEFT(c.contact_name,1)) AS initials, DATE_FORMAT(c.created_date,'%%b %%Y') AS customer_since, IF(c.status='Active','Active','Inactive') AS status_label, COUNT(o.order_id) AS open_order_count FROM contacts c LEFT JOIN orders o ON o.contact_id = c.contact_id AND o.status = 'open' WHERE c.contact_id = '%contact_id%' AND c.dept_id = '%deptid%' GROUP BY c.contact_id LIMIT 1 ]]></query> </sql> <div class="detail-card"> <div class="detail-header"> <div class="detail-avatar">%initials%</div> <div> <div class="detail-name">%contact_name%</div> <div class="detail-role">%job_title% · %department%</div> </div> <div class="detail-status">%status_label%</div> </div> <div class="detail-body"> <div> <div class="detail-field-label">Email</div> <div class="detail-field-value">%email%</div> </div> <div> <div class="detail-field-label">Phone</div> <div class="detail-field-value">%phone%</div> </div> <div> <div class="detail-field-label">Open Orders</div> <div class="detail-field-value">%open_order_count%</div> </div> <div> <div class="detail-field-label">Customer Since</div> <div class="detail-field-value">%customer_since%</div> </div> </div> </div> </block>
What's different about single-row data
<block>. It's transparent — it emits no tag of its own — and it's what makes a block-level <sql> legal at all: <sql> sits as a direct child of <block>, never nested inside one of the layout <div>s.<block>, before the markup that reads its tokens. Put it at the bottom and every %token% above it renders as literal, unresolved text — no error, just the raw %contact_name% printed on the page. (Inside a dynamiclist it's the other way round: there the query follows the row template.)type="row" — just ordinary HTML tags with the query's columns referenced as tokens directly.The pattern so far
Three posts in, and the shape is already clear: every read operation on the platform is the same idea — a query, a template, tokens standing in for columns — adjusted for how many rows come back and how they need to be laid out. Many free-form rows: dynamiclist. Many structured rows: dynamiclisttable. Exactly one row, values used freely: block-level SQL, no wrapper at all. Reading data was never the hard part of building a web application — it's writing it back that usually is, which is where the next two posts go.
Building a Form: a modal that adds a new Contact
Post 6 covers input for the first time — a modal form, its fields, its validation, and everything the engine generates from a single registration.