Custom Card Development Best Practices
Overview
Custom cards extend ThoughtFarmer's functionality through a plugin system. Following these best practices ensures your customizations remain stable and functional across ThoughtFarmer upgrades.
Core Principle: ThoughtFarmer is a Product, not a Platform. This means internal implementations may change between versions. Always use official APIs and documented interfaces to ensure upgrade compatibility.
Table of Contents
API Usage
Use Official APIs Only
Always interact with ThoughtFarmer through official channels:
- Custom Card API - For custom card development and integration
- ThoughtFarmer REST API - For data access and operations
Why Official APIs Matter
❌ Don't: Use internal core API calls or undocumented endpoints
// DON'T - Internal API signature may change const page = ctx.contentStore.getContent();
✅ Do: Use the official API
// DO - Stable, documented interface - everything under customPortlets is official for customization purposes const page = ctx.customPortlets.getPage();
Why?
- Internal APIs can change without notice
- Method signatures may be modified
- Endpoints may be refactored or removed
- Official APIs are versioned and backwards-compatible
Missing Functionality?
If the Custom Card API or REST API doesn't provide the functionality you need:
- Contact support: Either through email or our Helpdesk portal
- Submit a feature request: Explain your use case
- Wait for official implementation: The ThoughtFarmer team can add it as a forwards-compatible feature
This ensures your customization will be supported in future versions.
CSS and Styling
Unique Class Names
Always use unique, descriptive class names with a consistent prefix.
❌ Don't: Use generic class names
.table { /* Too generic, may conflict */ }
.header { /* Could clash with core styles */ }
.button { /* Not specific enough */ }
✅ Do: Use prefixed, descriptive class names
.acme-data-table { /* Clear, unique, prefixed with org name */ }
.acme-glossary-header { /* Specific to your card */ }
.acme-glossary-action-button { /* Descriptive and unique */ }
Recommended approach: Use your organization name or project identifier as a prefix to ensure uniqueness.
Never Target Core Product Classes
ThoughtFarmer's internal CSS classes and DOM structure are not guaranteed to be stable.
❌ Don't: Target or override ThoughtFarmer classes
/* DON'T - These classes may change or disappear */
.tf-portlet-header { color: red; }
.tf-content-item { margin: 20px; }
div[class^="tf-"] { padding: 10px; }
❌ Don't: Rely on core DOM structure
/* DON'T - Element hierarchy may change */
.tf-main-content div .my-custom-card { }
✅ Do: Style only your own components
/* DO - Self-contained styles */
.acme-my-card-container {
padding: 20px;
background: #f5f5f5;
}
.acme-my-card-title {
font-size: 1.5em;
font-weight: bold;
}
Replicating ThoughtFarmer Styles
If you need to match ThoughtFarmer's look and feel:
✅ Do: Copy styles into your component
// Copy the styles you need into your card's SCSS
.acme-my-button {
// Styles copied from ThoughtFarmer's button appearance
padding: 8px 16px;
border-radius: 4px;
background-color: #0066cc;
color: white;
&:hover {
background-color: #0052a3;
}
}
Trade-off: Your styling may diverge slightly from core styles after upgrades, but your component will continue to function. This is preferable to broken or missing styles.
Custom CSS Applies Everywhere
This applies to both:
- Custom card component styles
- Theme customizations via Custom CSS editor
Never target ThoughtFarmer classes in either context.
Adding Components Outside Custom Card Areas
Never Manipulate the DOM Directly
ThoughtFarmer is a Single Page Application (SPA) built with React. Directly manipulating the DOM with JavaScript or jQuery will cause bugs and UI issues.
❌ Don't: Use DOM manipulation APIs
// DON'T - Will cause React reconciliation issues
document.getElementById('main-content').appendChild(myElement);
document.querySelector('.tf-header').innerHTML = '<div>My content</div>';
$('.tf-sidebar').append('<div>My widget</div>');
❌ Don't: Modify ThoughtFarmer's DOM structure
// DON'T - React will not be aware of these changes
const header = document.querySelector('.tf-page-header');
header.style.display = 'none';
Use Official Placement APIs
✅ Do: Use the ctx.customPortlets.add() API to inject content into the page layout
// DO - Properly integrates with React
ctx.customPortlets.add('<h1>An important message!</h1>', {
placement: tf.portlets.Placement.LaneCenter,
position: tf.portlets.Position.Top,
});
Available Placement Options
placement - Where the portlet should be displayed:
-
tf.portlets.Placement.LaneLeft- Left column -
tf.portlets.Placement.LaneCenter- Center column -
tf.portlets.Placement.LaneRight- Right column (default) -
tf.portlets.Placement.PageHeader- Page header area -
tf.portlets.Placement.PageControls- Page controls area -
tf.portlets.Placement.SocialControls- Social controls area -
tf.portlets.Placement.SiteFooter- Site footer -
tf.portlets.Placement.SiteHeader- Site header -
tf.portlets.Placement.ProfileFieldGroups- Profile field groups section -
tf.portlets.Placement.AppToolBar- Application toolbar
position - Order within the placement (applies to LaneLeft, LaneCenter, LaneRight, ProfileFieldGroups):
-
tf.portlets.Position.Top- Top of the area -
tf.portlets.Position.Bottom- Bottom of the area (default) - Integer value - Specific position (larger numbers are further from top)
Example: Adding Content to Multiple Locations
// Add a banner to the page header
ctx.customPortlets.add(
'<div class="acme-banner">Important announcement</div>',
{
placement: tf.portlets.Placement.PageHeader,
position: tf.portlets.Position.Top
}
);
// Add a widget to the left sidebar
ctx.customPortlets.add(
'<div class="acme-quick-links">Quick Links...</div>',
{
placement: tf.portlets.Placement.LaneLeft,
position: 1
}
);
// Add a footer message
ctx.customPortlets.add(
'<div class="acme-footer-message">© 2024 ACME Corp</div>',
{
placement: tf.portlets.Placement.SiteFooter,
position: tf.portlets.Position.Bottom
}
);
Why This Matters
Using the official customPortlets API ensures:
- React is aware of your changes
- Your content won't be removed during re-renders
- No conflicts with React's virtual DOM
- Proper lifecycle management
- Future compatibility as the SPA evolves
Testing and Quality Assurance
Test Your Custom Cards
Thorough testing helps ensure your custom cards continue to work after ThoughtFarmer upgrades:
- API contract tests: Verify you're using documented API endpoints
- CSS isolation tests: Ensure your styles don't depend on external classes
- Functionality tests: Confirm features work with official APIs only
- Integration tests: Test the complete user workflow
Write Defensive Code
Since you won't be able to test against new ThoughtFarmer versions before they're deployed, write defensive code:
- Handle API errors gracefully - Don't assume API calls will always succeed
- Use try-catch blocks - Prevent exceptions from breaking your card
- Validate API responses - Check that responses contain expected data
- Provide fallback UI - Show meaningful messages when data isn't available
- Test edge cases - Handle empty data, network failures, and permission errors
Deployment Considerations
Build Output
Custom cards can be built using different approaches:
-
React components -
.jsfile with React component code -
HTML + JavaScript -
.htmlfile with embedded or linked JavaScript -
Styles -
.cssfile for styling
Regardless of approach, ensure your custom card is:
- Self-contained - All dependencies bundled or loaded via official SDKs
- Production-ready - Minified and optimized where appropriate
- API-compliant - Uses only official APIs (regardless of whether you're using React, vanilla JS, or HTML)
Version Compatibility
When deploying custom cards:
- Document ThoughtFarmer version compatibility - Note which version you developed and tested against
- Review ThoughtFarmer release notes - Check for API changes or deprecations
- Plan for graceful degradation - Handle scenarios where APIs may be temporarily unavailable
- Maintain backwards compatibility - Design cards to work across minor version updates
Monitoring and Maintenance
As a SaaS customer, you won't have access to test against new ThoughtFarmer versions before they're deployed. This makes defensive coding practices critical:
After ThoughtFarmer upgrades:
- Monitor immediately for issues - Check your custom cards as soon as possible after an upgrade
- Watch browser console - Look for errors, warnings, or failed API calls
- Test critical workflows - Verify key functionality still works as expected
- Have a rollback plan - Be prepared to temporarily disable problematic custom cards if needed
Proactive strategies:
- Review release notes regularly - Stay informed about upcoming changes to APIs
- Use error boundaries - Prevent custom card failures from breaking the entire page
- Implement logging - Track errors and API failures for troubleshooting
- Keep dependencies minimal - Fewer dependencies mean fewer things that can break
- Follow official APIs strictly - This is your best protection against breaking changes
Summary: The Golden Rules
- ✅ Use official APIs only - Custom Card API and REST API (applies to React, vanilla JS, and HTML)
- ✅ Use unique prefixed class names - e.g.,
yourorg-card-name - ✅ Never target ThoughtFarmer classes - Not in CSS or selectors
- ✅ Copy styles when needed - Don't extend core styles
- ✅ Never manipulate the DOM directly - Use
ctx.customPortletsAPIs instead - ✅ Avoid internal APIs - Even if they seem convenient
- ✅ Request missing features - Contact our Help Desk
- ✅ Test thoroughly - Especially API integrations and upgrades
- ✅ Document dependencies - Note which APIs and versions you use
Additional Resources
Need Help?
If you need functionality that isn't available through official APIs:
- Contact: Our Help Desk email or portal
- Subject: Custom Card Feature Request
- Include: Your use case and desired functionality
The ThoughtFarmer team can add features officially, making them forwards-compatible and safe for long-term use.
Remember: Following these practices protects your investment in customizations and ensures smooth ThoughtFarmer upgrades for years to come.
Comments
0 comments
Please sign in to leave a comment.