Building a Reusable Library of Dashboard Blocks
This guide demonstrates how to transform your existing dashboard charts into reusable components for your organization's Block Library. By creating a well-structured library of blocks, you empower dashboard builders to easily discover, implement, and customize sophisticated visualizations with minimal effort.
Why Create a Block Library?
Your Block Library will:
- Provide consistent visualization patterns across your organization.
- Reduce duplication of effort in dashboard creation.
- Enable less technical users to create sophisticated dashboards.
- Establish governance over analytical presentation standards.
Dashboard builders can now:
- Browse the Block Library. filter by category and search for relevant blocks.
- Add your blocks to their dashboards with a few clicks.
- Customize parameters through an intuitive interface.
- Create professional visualizations without writing complex code.
Here's what the experience looks like for dashboard builders using your library blocks:
Step-by-Step Process
1. Refactor Your Chart into a Function
The first step is to isolate your visualization logic by moving it into a dedicated function. This encapsulation is essential for reusability.
// Before: Chart logic directly in the dashboard
Dashboard saas {
block v1: VizBlock {
// Chart logic here
}
}
// After: Refactored into a function
Func mrr_breakdown() {
VizBlock {
// Chart logic moved here
}
}
Dashboard saas {
// Reference the function in your dashboard
block v1: mrr_breakdown()
}
This separation creates a clean boundary between the chart's implementation and its usage.
2. Register Your Component with @template
To make your function appear in the library, add the @template
decorator above it. This decorator transforms an ordinary function into a discoverable, reusable block. Note that a function must return an Anlytics Block in order for it to appear in the library.
@template(
title = "MRR & PoP Growth", // Clear, descriptive name
description = "VHow does your revenue evolve over time and compare to last year?", // Explain what it does
thumbnail = "https://link.to/image.png" // Custom preview image (optional)
)
Func mrr_breakdown() {
VizBlock {
// Chart implementation
}
}
Key considerations:
- Title: Choose a descriptive name that clearly indicates the block's purpose
- Description: Explain what insights the visualization provides
- Thumbnail: While optional, a custom thumbnail helps users quickly identify your block
Once decorated, your block will automatically appear in the library and become available to all dashboard builders.
3. Define Customizable Parameters
To make your block truly flexible, replace hardcoded values with parameters. This allows dashboard builders to adapt the block to their specific needs without modifying its core logic. You can use any of the AML Types for parameters.
// Before: Hardcoded values
Func mrr_breakdown() {
VizBlock {
// ...
}
}
// After: Parameterized for flexibility
Func mrr_breakdown(
dataset: Dataset,
mrr_amount: VizFieldRef,
break_down_dimension: VizFieldRef,
date_field: VizFieldRef,
comparison_period: Number
) {
VizBlock {
// ...
}
}
Provide default values for parameters to ensure the block works out of the box.
When users add it to their dashboards, the block will just work with the default values, without them having to configure anything. This side-steps the problem of users having to read, understand and specify each parameter before a block can be used.
// With default values
Func mrr_breakdown(
dataset: Dataset = saas_dataset,
mrr_amount: VizFieldRef = ref('mrr_transactions', 'mrr_amount'), // a metric in a model
break_down_dimension: VizFieldRef = ref('mrr_transactions', 'subscription_type'), // a dimension in a model
date: VizFieldRef ref('mrr_transactions', 'subscription_type') // a dimension a model
comparison_period: Number = 12
) {
VizBlock {
// ...
}
}
When dashboard builders edit a block, they will be configured with the default values you provided. This ensures a smooth experience for users who want to use the block without any configuration.)
Parameter best practices:
- Provide sensible defaults where appropriate.
- Consider what aspects users will most likely want to customize.
- Balance flexibility with simplicity. Too many parameters can be overwhelming.
4. Implement Parameter References
Update your function to use the parameters so that your block can be dynamic. Use string interpolation to incorporate parameters in AQL field definition.
Func mrr_breakdown(
dataset: Dataset = saas_dataset,
mrr_amount: VizFieldRef = ref('mrr_transactions', 'mrr_amount'),
break_down_dimension: VizFieldRef = ref('mrr_transactions', 'subscription_type'),
date: VizFieldRef ref('mrr_transactions', 'subscription_type'),
comparison_period: Number = 12
) {
VizBlock {
viz: CombinationChart {
// Use dataset parameter
dataset: dataset,
calculation metric {
// Use mrr_amount parameter in field formula with string interpoloation
formula: @aql sum(${mrr_amount.model}.${mrr_amount.field}),
}
legend: VizFieldFull {
// Use break_down_dimension parameter
ref: break_down_dimension
format {
type: 'text'
}
}
filter {
// Use other parameters
field: date
operator: 'last'
value: comparison_period
modifier: 'month'
}
}
}
}
Ensure all hardcoded values that might need customization are replaced with parameter references. Here are some values that might want to customize:
- Dataset names.
- Field references.
- Field formula.
- Filter values.
- Visual properties (colors, labels, etc.).
5. (Advanced) Enhance with Comprehensive Metadata
You may want to add detailed metadata to guide users on how to effectively use your block. This creates a self-documenting component that's easier to discover and implement correctly.
@template(
title = "MRR & PoP Growth",
description = "Visualize monthly recurring revenue with period-over-period comparison",
thumbnail = "https://link.to/image.png",
metadata = {
// Categorize your block for easier discovery
group: 'SaaS Metrics',
// Specify default dimensions when added to a dashboard
block_width: 620,
block_height: 460,
// Document each parameter
func: TemplateFuncMetadata {
param dataset: GeneralParamMetadata {
description: 'The dataset containing your revenue information'
},
param mrr_amount: GeneralParamMetadata {
description: 'The field containing monthly recurring revenue values'
},
param date_field: GeneralParamMetadata {
description: 'The date field to use for time series analysis'
},
// Useful when a block needs color customization, Holistics will display a color picker
// for dashboard builders so that they đon't have to input HEX code
param third_bin_color: StringParamMetadata {
input_type: 'color-picker'
}
}
}
)
Effective metadata includes:
- Grouping: Logical categorization for easier discovery
- Size specifications: Default dimensions when added to a dashboard
- Parameter documentation: Clear descriptions of each parameter's purpose
- Examples: Sample values to guide users
Best Practices for Block Library Development
- Test your block. Before publishing to the library, test your block with various parameter combinations to ensure it behaves as expected in all scenarios.
- Maintenance. Consider how you'll handle updates to your blocks. Major changes might warrant a new block rather than modifying an existing one that's already in use.
- Documentation. Beyond the in-code metadata, maintain comprehensive documentation about your block library, including when to use specific blocks, common customization patterns, real-world examples.
Conclusion
By following these steps, you've created a powerful, self-documented, and customizable block that others can easily discover, understand, and reuse across dashboards.