ChartHop by ChartHop
Dashboards
Building HTML Tables in Text Blocks
text blocks in charthop dashboards support raw html, which means you can build a fully formatted, styled table using a \<table class="ch table 1"> element combined with cqlt (template expressions) this is especially useful when you need a custom multi row table that responds to dashboard filters — but where the native chart types don't give you exactly the layout you want when to use this you want a table that displays computed metrics side by side (e g , review scores across multiple categories) you need 20+ versions of the same dashboard with different filters — and want one flexible text block that adapts to jobfilter , rather than rebuilding native chart tables for each version the data you're displaying comes from long or complex cql expressions (like custom scoring calculations) that don't map cleanly to a native chart formula how it works inside a text block, you can write html directly charthop will render it as formatted content wrap any cql expression in {{ }} to have it evaluated dynamically — just like you would in any other template expression the class ch table 1 applies charthop's standard table styling, so your table visually matches the rest of the dashboard basic structure categoryscoreoverall performance{{ findanswersbyassessment('managerreviewrating', 'h1 performance review') filter{target department=jobfilter} mean{value} }}values alignment{{ findanswersbyassessment('valuesratingmanager', 'h1 performance review') filter{target department=jobfilter} mean{value} }} available variables text blocks have access to three key dashboard variables that make your table dynamic and filter aware variable what it represents jobfilter the audience/filter the dashboard viewer has currently applied (e g , filtered to engineering, or a specific manager's team) intervalfrom the start of the reporting period selected on the dashboard (inclusive) intervaluntil the end of the reporting period selected on the dashboard (exclusive — i e the day after the last day in the period) using all three means your table responds fully to whatever the viewer has configured — both in terms of who is in scope and when these are the same variables used in time series chart formulas, so if you're already familiar with intervalfrom / intervaluntil from building charts, they work exactly the same way here example using all three variables {{ findhires(intervalfrom, intervaluntil) filter{jobfilter} count() }} this counts new hires within the selected date range, scoped to the active filter using jobfilter inside the table because this is a text block, the jobfilter variable is available — it reflects whatever filter the dashboard viewer has currently applied (e g , filtered to engineering, or a specific manager's team) you can pass jobfilter directly into your cql expression {{ db job find(jobfilter) mean{basecomp annualized} }} this means a single text block table can power 20+ filtered dashboard versions without any changes — just apply a different audience or department filter on the dashboard itself real world example multi score review summary table this example displays average scores across several review dimensions, filtered to whoever is in scope review dimensionavg scoreoverall performance{{ findanswersbyassessment('managerreviewrating', 'h1 2025 review') filter{jobfilter} mean{value} }}impact{{ findanswersbyassessment('impactcompetency', 'h1 2025 review') filter{jobfilter} mean{value} }}collaboration{{ findanswersbyassessment('collaborationcompetency', 'h1 2025 review') filter{jobfilter} mean{value} }}knowledge{{ findanswersbyassessment('knowledgecompetency', 'h1 2025 review') filter{jobfilter} mean{value} }} tips always use ch table 1 as the class — this applies charthop's built in table styling and keeps it visually consistent with native chart tables column headers are static html — only the cell values need template expressions keep headers as plain text in \<th> tags expressions are evaluated server side — if a formula returns no data (e g , no responses exist for a filter), the cell will render as empty rather than erroring this does not replace native table charts for most use cases — if the built in table chart type works for you, use it this approach shines when you need custom layouts, multi source data in one table, or highly specific expression logic that the native chart type can't express
