Config Driven UI
Config-driven UI means generating an interface from configuration and data instead of manually hardcoding every section.
Config + Data
↓
Rendering Logic
↓
Reusable Components
↓
Dynamic UI
One-line idea: The configuration describes what to render, while reusable components decide how it appears.
Core Concepts
The Problem with Hardcoded UI
A small interface may begin with manually repeated components:
<Card />
<Card />
<Card />
As the application grows, this approach creates problems:
- repeated markup increases
- layouts become harder to manage
- changing section order requires code changes
- customization becomes difficult
- supporting multiple UI variations takes extra effort
Config-driven UI moves the repeated structure into data:
const sections = [
{ id: "one", type: "card" },
{ id: "two", type: "card" },
{ id: "three", type: "card" },
];
The frontend reads the configuration and renders the matching components.
What Is UI Configuration?
A UI configuration is a data structure that describes the sections of an interface.
const pageConfig = [
{
id: "hero",
type: "banner",
data: {
title: "Summer Collection",
description: "Explore the latest products",
},
},
{
id: "recommended",
type: "scrollableRow",
title: "Recommended for You",
data: recommendedProducts,
},
];
The configuration can control:
- component type
- content or data
- section order
- enabled or disabled sections
- component variation
- layout selection
Config and Data
Config and data have related but different jobs.
| Value | Responsibility |
|---|---|
type | Selects the component to render |
data | Supplies the content displayed by that component |
variant | Chooses a visual or behavioral variation |
enabled | Controls whether the section is shown |
| Array order | Controls the order of sections |
Example:
{
type: "scrollableRow",
variant: "movie",
enabled: true,
data: movies
}
type -> render ScrollableRow
variant -> use movie-style cards
enabled -> show the section
data -> display the movie items
Type-Based Rendering
The type field is the core of the rendering decision.
type = "card" -> Card
type = "banner" -> Banner
type = "scrollableRow" -> ScrollableRow
A simple renderer can use conditional logic:
export default function SectionRenderer({ section }) {
if (section.type === "banner") {
return <Banner data={section.data} />;
}
if (section.type === "scrollableRow") {
return (
<ScrollableRow
title={section.title}
data={section.data}
variant={section.variant}
/>
);
}
if (section.type === "card") {
return <Card data={section.data} variant={section.variant} />;
}
return null;
}
Different configuration values produce different UI without manually rewriting the page.
Independence and Flexibility
When the interface depends on configuration:
- sections can be reordered
- layouts can change
- sections can be enabled or disabled
- the same component can display different data
- one rendering system can support multiple UI variations
Fixed page structure
↓
Configurable rendering system
↓
More freedom to change the interface
The frontend becomes a reusable system rather than a collection of fixed pages.
Practical Config-Driven Patterns
Build a Page Renderer
The page renderer loops through the configuration and delegates each section to a section renderer.
export default function PageRenderer({ config }) {
return (
<main>
{config.map((section) => (
<SectionRenderer key={section.id} section={section} />
))}
</main>
);
}
const homePageConfig = [
{
id: "main-banner",
type: "banner",
data: {
title: "Discover New Arrivals",
description: "Fresh products selected for you",
},
},
{
id: "popular-products",
type: "scrollableRow",
title: "Popular Products",
variant: "product",
data: popularProducts,
},
];
export default function HomePage() {
return <PageRenderer config={homePageConfig} />;
}
Rendering flow:
HomePage passes config
↓
PageRenderer reads every section
↓
SectionRenderer checks its type
↓
Banner or ScrollableRow renders
Use a Component Registry
As the number of section types increases, a component registry keeps the mapping in one place.
export const sectionRegistry = {
banner: Banner,
card: Card,
scrollableRow: ScrollableRow,
};
import { sectionRegistry } from "./sectionRegistry";
export default function SectionRenderer({ section }) {
if (section.enabled === false) {
return null;
}
const Component = sectionRegistry[section.type];
if (!Component) {
return null;
}
return <Component {...section} />;
}
The registry connects configuration types to reusable React components.
"banner" -> Banner
"card" -> Card
"scrollableRow" -> ScrollableRow
Config-Driven Scrollable Row
A scrollable row is reusable because its content comes from configuration.
const movieRowConfig = {
id: "trending-movies",
type: "scrollableRow",
title: "Trending Movies",
variant: "movie",
data: movies,
};
export default function ScrollableRow({ title, data, variant }) {
return (
<section className="scrollable-row">
<h2>{title}</h2>
<div className="scrollable-row__items">
{data.map((item) => (
<Card key={item.id} data={item} variant={variant} />
))}
</div>
</section>
);
}
The same component can render:
- products
- movies
- recommendations
- donation cards
- dashboard content
Only the configuration and data need to change.
Multiple UI Variations
One reusable component can support multiple presentations through a variant value.
<Card variant="movie" data={movie} />
<Card variant="product" data={product} />
<Card variant="donation" data={campaign} />
The variation can also come from configuration:
const section = {
type: "scrollableRow",
variant: "donation",
data: donationCampaigns,
};
export default function Card({ data, variant }) {
return (
<article className={`card card--${variant}`}>
<img src={data.image} alt={data.title} />
<h3>{data.title}</h3>
{variant === "product" && <p>₹{data.price}</p>}
{variant === "movie" && <p>{data.rating}/10</p>}
{variant === "donation" && <p>{data.progress}% funded</p>}
</article>
);
}
Same component structure
+
Different variant and data
↓
Different UI presentation
Enable or Disable Sections
Configuration can control whether a section is visible.
const pageConfig = [
{
id: "offer-banner",
type: "banner",
enabled: false,
data: offer,
},
{
id: "products",
type: "scrollableRow",
enabled: true,
data: products,
},
];
The renderer ignores disabled sections:
if (section.enabled === false) {
return null;
}
This changes the visible page without rewriting its JSX structure.
Change Section Order
When a page is rendered from an array, the array order becomes the UI order.
const firstLayout = [bannerSection, productSection, movieSection];
const secondLayout = [movieSection, bannerSection, productSection];
Config order changes
↓
Rendered section order changes
This makes page layouts more customizable.
Data-Driven Updates
Components do not need to be manually rewritten when their content changes.
const config = {
type: "card",
data: {
title: "Old title",
},
};
When data.title changes, the same card component renders the new title.
Config changes
Data changes
↓
React receives new props
↓
The UI updates
Benefits, Trade-Offs and Common Mistakes
Benefits
- reduces manually repeated page markup
- makes section ordering flexible
- supports reusable components and layouts
- allows sections to be enabled or disabled
- supports multiple visual variations
- separates page structure from component rendering
- makes large interfaces easier to customize
Trade-offs
| Simple hardcoded UI | Config-driven UI |
|---|---|
| Direct and easy for a very small fixed page | Better for repeated or changeable layouts |
| Structure is visible directly in JSX | Structure is split between config and renderer |
| Changes require editing the page | Many changes can be made through config |
| Repetition grows across similar pages | Reusable renderers reduce duplication |
Config-driven UI is most useful when several screens share components or when content, order and variations change. A small fixed screen may not need the extra rendering layer.
Common mistakes
| Mistake | Better approach |
|---|---|
| Hardcoding every repeated section | Store repeated structure in configuration |
| Rendering all types in the page component | Use a dedicated section renderer |
| Using one component for every possible layout | Create focused reusable components and variants |
| Mixing content directly into rendering conditions | Keep content in data |
Ignoring unknown type values | Return a safe fallback or skip the section |
Repeating long if chains as types grow | Keep type-to-component mappings in a registry |
| Forgetting stable keys for configured sections | Give every section a stable id |
Interview Revision
Quick Revision Checklist
- Config-driven UI generates components from configuration and data.
typeselects which component should render.datasupplies the component's content.variantsupports multiple presentations of a reusable component.enabledcan control section visibility.- Array order can control rendered section order.
- A page renderer loops through the section configuration.
- A section renderer maps each type to a component.
- A component registry keeps type mappings organized.
- Reusable components reduce repeated layout code.
- The same scrollable row can display different content types.
- Config changes and data changes produce UI changes.
Frequently Asked Interview Questions
1. What is config-driven UI?
Config-driven UI is an approach where the frontend reads configuration and data to decide which components to render instead of manually hardcoding every section of a page.
2. Why use config-driven UI?
It reduces repeated code and makes layouts, ordering, visibility and component variations easier to customize as an application grows.
3. What is the purpose of the type field?
The renderer uses type to select a component. For example, banner renders Banner, while scrollableRow renders ScrollableRow.
4. What is the difference between config and data?
Config describes the UI structure and rendering choices. Data supplies the actual content displayed inside the selected components.
5. How does a component registry help?
A registry stores the mapping between configuration types and React components in one place. The renderer can look up the correct component instead of maintaining a growing list of conditions.
6. How can one component support multiple designs?
Pass a variant through configuration. The component uses that value to select the appropriate styling or content presentation while keeping its reusable structure.
7. How can configuration control page order?
Store page sections in an array and render them with map. Reordering the array changes the order of the rendered sections.
8. When is config-driven UI most useful?
It is useful for large or customizable interfaces with repeated sections, multiple layouts, changing order, reusable rows or several variations of the same component.
9. What is the main rendering flow?
The frontend receives config and data, the renderer checks each section type, the matching reusable component receives the section data, and React produces the final UI.
Memory Trick
Describe -> Select -> Supply -> Render
Describe the page with config
Select a component using type
Supply its content through data
Render the final dynamic UI
One-Line Summary
Config-driven UI turns reusable React components into a flexible rendering system controlled by configuration and data.
Final Mental Model
Page configuration arrives
↓
PageRenderer loops through sections
↓
SectionRenderer reads each type
↓
Registry selects a reusable component
↓
Data and variant become component props
↓
Components render the final UI