Overview & Component Creation
Introduction
Section titled “Introduction”Components in NETWRIX are Astro files located in src/components/ organized by type (card, hero, cta, etc.). In this section, you’ll build CardTest - a simple card component with media, title, and subtitle using custom NETWRIX components.
Creating Your First Component
Section titled “Creating Your First Component”Component Structure
Section titled “Component Structure”Create the file: src/components/card/CardTest.astro
---import { Asset } from "@terrahq/astro-core";import Btn from "@components/btn/Btn.astro";
const { payload: { customClass, title, subtitle, media, link, language }} = Astro.props;---
<Btn language={language} payload={{ button: { ...link, }, customContent: true, customClass: ["c--card-test", customClass].filter(Boolean).join(" "), }}> <div class="c--card-test__media-wrapper"> <Asset payload={{ ...media, decodingAsync: media?.decoding, customClass: "c--card-test__media-wrapper__media", sizes: "80px", }} /> </div> <div class="c--card-test__wrapper"> {title && <h2 class="c--card-test__wrapper__title">{title}</h2> } {subtitle && <p class="c--card-test__wrapper__subtitle">{subtitle}</p> } </div></Btn>Understanding the Structure
Section titled “Understanding the Structure”Frontmatter (Script Section)
Section titled “Frontmatter (Script Section)”---import { Asset } from "@terrahq/astro-core";import Btn from "@components/btn/Btn.astro";
const { payload: { customClass, title, subtitle, media, link, language } } = Astro.props;---Key Imports:
- Asset: Terra’s component for handling images and media with responsive optimization
- Btn: NETWRIX’s button wrapper that handles links, buttons, and clickable containers
Props Destructuring:
We extract props from Astro.props.payload - this is the standard pattern for NETWRIX components. The payload contains all the component’s configuration data.
Template Structure
Section titled “Template Structure”The component follows BEM (Block Element Modifier) naming convention:
c--card-test ← Block├── c--card-test__media-wrapper ← Element│ └── c--card-test__media-wrapper__media ← Sub-element└── c--card-test__wrapper ← Element ├── c--card-test__wrapper__title ← Sub-element └── c--card-test__wrapper__subtitle ← Sub-elementClass Naming Pattern:
c--prefix indicates Componentcard-testis the component name__separates block from element--separates block/element from modifier (e.g.,c--card-test--dark)
Why Wrap with Btn?
Section titled “Why Wrap with Btn?”The <Btn> component wrapper provides essential functionality:
✅ Consistent link/button behavior
✅ Accessibility features (ARIA attributes)
✅ Keyboard navigation support
✅ Proper semantic HTML (<a> vs <button>)
✅ Modal and anchor functionality
By using customContent: true, we can pass custom HTML as children instead of just a text label, making the entire card clickable.
<Btn payload={{ button: { ...link }, customContent: true, // ← Enables custom HTML content }}> <!-- Your custom card structure here --></Btn>Asset Component Integration
Section titled “Asset Component Integration”<Asset payload={{ ...media, decodingAsync: media?.decoding, customClass: "c--card-test__media-wrapper__media", sizes: "80px", }}/>The Asset component handles:
- ✨ Responsive images with
srcset - 🚀 Lazy loading for performance
- ♿ Proper
altattributes for accessibility - 🖼️ WebP format with fallbacks
Important Parameters:
...media- Spreads all media properties from CMS (url, alt, type, etc.)decodingAsync- Tells browser to decode image asynchronously (better performance)customClass- Your custom CSS class for stylingsizes- Tells browser the display size for optimal image selection
Component Best Practices
Section titled “Component Best Practices”✅ Do’s
Section titled “✅ Do’s”1. Always destructure from payload
const { payload: { title, subtitle } } = Astro.props;2. Use conditional rendering for optional props
{title && <h2>{title}</h2>}{subtitle && <p>{subtitle}</p>}3. Filter empty classes when combining
customClass: ["c--card-test", customClass].filter(Boolean).join(" ")4. Follow BEM naming strictly
class="c--card-test__wrapper__title"5. Spread media props to preserve all properties
<Asset payload={{ ...media, customClass: "..." }} />❌ Don’ts
Section titled “❌ Don’ts”1. Don’t hardcode values - use props
<!-- ❌ Bad --><h2>Welcome</h2>
<!-- ✅ Good -->{title && <h2>{title}</h2>}2. Don’t skip conditional checks for optional props
<!-- ❌ Bad - Will show empty <h2> if no title --><h2>{title}</h2>
<!-- ✅ Good -->{title && <h2>{title}</h2>}3. Don’t mix naming conventions
<!-- ❌ Bad -->class="card-test_wrapper-title"
<!-- ✅ Good -->class="c--card-test__wrapper__title"4. Don’t forget to spread media props
<!-- ❌ Bad - Loses alt, type, and other properties --><Asset payload={{ url: media.url }} />
<!-- ✅ Good --><Asset payload={{ ...media, customClass: "..." }} />Props Interface
Section titled “Props Interface”Understanding the expected props structure:
interface CardTestProps { payload: { customClass?: string; // Optional additional CSS class title: string; // Card title subtitle?: string; // Optional card subtitle language: string; // Current language (e.g., "en") media: { // Media object type: "Image"; url: string; alt: string; decoding?: boolean; }; link: { // Button/link configuration label: string; url: string; target: "_self" | "_blank"; option?: string; }; };}Understanding Custom Components
Section titled “Understanding Custom Components”Btn Component
Section titled “Btn Component”Btn (src/components/btn/Btn.astro) is a custom wrapper around Terra’s ButtonLink that extends its functionality to handle links, modals, and anchors. It supports custom icons (arrow-right, arrow-left, arrow-top, play, download) and enables wrapping custom HTML content by setting customContent: true, which is essential for making entire cards clickable. To understand how it works, review the ButtonLink documentation in Astro Core.
Asset Component
Section titled “Asset Component”Asset (from @terrahq/astro-core) is Terra’s image optimization component that automatically handles responsive images with srcset, WebP format conversion, lazy loading, and proper accessibility attributes. The key parameters are decodingAsync for better performance, customClass for styling, and sizes to help the browser select the optimal image. For complete details, check the Asset Component documentation.
Component Usage Example
Section titled “Component Usage Example”Here’s how you would use the CardTest component in a module or page:
<CardTest payload={{ language: "en", title: "Cloud Security", subtitle: "Enterprise-grade security solutions for your data", customClass: "my-custom-modifier", media: { type: "Image", url: "/images/security-icon.webp", alt: "Cloud Security Icon", decoding: true }, link: { label: "Learn More", url: "/services/cloud-security", target: "_self" } }}/>Next Steps
Section titled “Next Steps”Now that you’ve created your component structure, it’s time to add styling!
👉 Continue to Styling with CSS & SCSS to learn how to style your component using the NETWRIX design system.