Crafting Clean UI: Reusable Card Components in FlyntWP with Twig
If you've spent any time battling slow page builders, wrestling with their generated mountain of div soup, or just generally feeling limited by their low-code straitjacket, then you understand the frustration. We're constantly chasing better performance and cleaner code, but often feel like we're fighting our own tools. That’s exactly where FlyntWP shines, offering a breath of fresh air with its programmatic, component-driven approach. Today, I want to dive into one of FlyntWP’s superpowers: building truly reusable UI components with Twig, and we'll do it by creating a simple "Card" component.
FlyntWP embraces a developer-first methodology. It lets us craft custom, modular blocks of UI using Twig templates, integrate them seamlessly with ACF Pro for content management, and then compile them at lightning speed with Vite. The result? A lean, mean, WordPress machine with a DOM structure so clean, your Core Web Vitals will thank you. No more endless nested divs, no more inline styles fighting for dominance, just pure, semantic HTML.
Let's get practical. Imagine we need a "Card" component – a common UI element featuring a title, some text, and perhaps a call-to-action link. Instead of building this from scratch every time or relying on a bloated page builder module, we create it once as a reusable Twig component.
First, within your FlyntWP theme's `Components` directory, you'd create a new folder, say `Card`. Inside `Card`, you'll typically have an `index.twig` file and a `functions.php` file. For a simple display component like our Card, `functions.php` might be minimal, perhaps just registering the component, but the magic happens in `index.twig`:
<div style="background-color:#eee; padding: 15px; border-radius: 5px; font-family: monospace; white-space: pre-wrap;"> {# Components/Card/index.twig #} {% set title = title ?? '' %} {% set text = text ?? '' %} {% set link_url = link_url ?? '' %} {% set link_text = link_text ?? 'Learn More' %}
<div class="card"> {% if title %} <h3 class="card__title">{{ title }}</h3> {% endif %} {% if text %} <p class="card__text">{{ text }}</p> {% endif %} {% if link_url and link_text %} <a href="{{ link_url }}" class="card__link">{{ link_text }}</a> {% endif %} </div> </div>
Notice a few things here: we're defining default values using the `??` operator, ensuring our component is robust even if some data isn't passed. The structure is clean, and our CSS classes (`card`, `card__title`, etc.) are ready for styling. This is the essence of a reusable component – it’s a self-contained unit that expects certain variables to be passed to it.
Now, how do we use this? Let's say we have a parent component, perhaps a `HeroSection` or a `CardGrid`, which needs to display one or more of these `Card` elements. We can include our `Card` component and pass it the necessary data directly. ACF Pro plays a vital role here; you'd typically define fields within your parent component's `functions.php` (e.g., using `add_row` for a repeater field of cards) to gather `title`, `text`, `link_url`, and `link_text` from the WordPress admin.
Then, in your parent component's `index.twig` file, you might render it like this:
<div style="background-color:#eee; padding: 15px; border-radius: 5px; font-family: monospace; white-space: pre-wrap;"> {# Components/CardGrid/index.twig (example parent component) #} <div class="card-grid"> {% for card in cards %} {# 'cards' would be an ACF Pro repeater field #} {% include 'Components/Card/index.twig' with { title: card.card_title, text: card.card_text, link_url: card.card_link.url, link_text: card.card_link.title } only %} {% endfor %} </div> </div>
Here, `cards` is the variable containing the data from our ACF repeater field. We loop through each `card` item and `include` our `Card` component, explicitly passing the data it expects. The `only` keyword is a nice touch, ensuring that only the specified variables are passed, keeping the component’s scope clean.
This approach delivers massive benefits. You get incredibly clean DOM structures, which are a cornerstone for excellent Core Web Vitals and SEO. Development becomes faster because you're reusing well-tested building blocks. Maintenance is a breeze; if you need to tweak the HTML structure of a card, you do it in one place, and the change propagates everywhere. Plus, with Vite under the hood, your build speeds are phenomenal, leading to a much snappier development experience.
Ditching the page builder bloat for a programmatic, component-driven workflow like this in FlyntWP isn't just about personal preference; it's about delivering superior performance, maintainability, and a developer experience that genuinely feels empowering. If you're ready to build WordPress sites that fly, both for your users and your development team, diving into Twig components with FlyntWP is your next essential step.