feature-image

Introduction

In the ever-evolving landscape of web development, creating seamless and personalised user experiences is a top priority. One powerful approach to achieve this in Next.js is through dynamic template selection. By dynamically choosing templates based on user attributes, roles, or other dynamic conditions, developers can craft more tailored and engaging interfaces. In this blog post, we’ll explore strategies for implementing dynamic template selection, unlocking the potential for personalised and adaptive web applications.

Understanding the need for Dynamic Templates

Static web pages offer a consistent experience for all users, but dynamic content and user-specific features often require a more flexible approach. With dynamic template selection, developers can adapt the user interface based on contextual information. This might include:

1.Template Based: Displaying different types of template based on the needs.

2.User Roles: Showcasing different layouts or features for administrators, regular users, or guests.

3.Device Types: Optimising the user interface for various devices, such as desktops, tablets, and mobile phones.

In this blog, we’ll explore the effective utilisation of Markdown files in a template-driven framework. Markdown, known for its simplicity and plain-text formatting, plays a crucial role in structured content management. This approach excels in extracting and parsing content, particularly metadata, making it highly systematic. By distinctly separating content from its presentation, it achieves a high degree of flexibility and simplifies ongoing maintenance.

Beyond mere content updates, this approach excels in offering dynamic user experiences tailored to specific scenarios. For instance, it can adjust the user experience based on flow within an application. This level of adaptability is particularly crucial for platforms aiming to provide a personalised user interface. Additionally, the scalability of this method is a key asset for larger projects. It guarantees uniformity in design and structure across numerous documents, essential for ensuring a cohesive user experience and maintaining brand consistency.

This template-centric approach is also remarkably user-friendly, catering to content creators who may not possess extensive technical expertise. It seamlessly integrates with static site generators, a feature that is especially advantageous for blog platforms or documentation websites.

Additionally, the templates are not only customizable to fit various content types but are also optimised for search engine visibility. This SEO-friendly aspect is crucial for enhancing the online presence of the content.

In essence, by marrying the simplicity and versatility of Markdown with a structured, template-based approach, this method presents a well-rounded solution for web projects. It adeptly balances structure, adaptability, and ease of use, making it an ideal choice for a wide array of web-based applications.

Gist: Getting Data from .md Files

In this below example we’re trying to get the content from our files(Markdown files) which are placed inside the content/articles directory. Since we need to extract some specific data from the .md files we’ve made the files in such a way that it can be used for our needs in the UI like title, featured image, date, tags etc.,


slug: env-variables-nextjs title: “Manage Multiple NEXT_PUBLIC Environment Variables at Runtime with Docker” date: 2023-01-17T01:29:14+05:30 featureImage: /images/blog/nextjs-env-vars/dockerimg.webp template: 2 tags:

  • Next JS
  • Docker
  • Environmental Variables

Context

Next.js is definitely a very good solution for making modern web applications. It’s fast, simple, and reliable. It works very well also with Docker, you can build a production image with a few lines of Dockerfile, and deploy your app to the world……….

The above is a sample .md file which we are using for our articles. As you can see we’ve defined what needs to be accessed from the UI and the rest of it will be taken care of by ReactMarkdown and SyntaxHighlighter. Now, you can customise your UI using the extracted data. We’ve created multiple templates for the blogs and articles and used them based on the selection(selected by the blog like “template : 2” in the .md file). Based on this we’re selecting the templates designed. Now let’s see the implementation of this.

Implementing Dynamic Template Selection

1.Install Required Packages npm i gray-matter react-syntax-highlighter react-markdown

Gray-matter: (https://www.npmjs.com/package/gray-matter) It is used to parse front-matter from a string or file. Fast, reliable and easy to use. Which has support for YAML, JSON, TOML or Coffee Front-Matter, with options to set custom delimiters.

React-syntax-highlighter: (https://www.npmjs.com/package/react-syntax-highlighter) Syntax highlighting component for React using the seriously super amazing lowlight and refractor by wooorm(https://github.com/wooorm)

React-markdown: (https://www.npmjs.com/package/react-markdown) This package is a React component that can be given a string of markdown that it’ll safely render to React elements. You can pass plugins to change how markdown is transformed and pass components that will be used instead of normal HTML elements.

2.Getting the data from the files Currently we’re using the Next.js framework (v.13.1.1). In your Next.js page or component file, use the getStaticProps function to fetch the Markdown data. This function will run at build time and provide the data as a prop to your component. And the implementation we have done is for the blogs and articles our company has been publishing every month. Every blog has its own need and unique way of portraying content. For that we’ve used this technique of dynamic template selection. Below is the javascript code for getting the data from your project (Note: Change the file directory as per your needs. Here we’ve placed it in the content/articles. And we’ve read from the .md files)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
export const getStaticProps = async () => {
  const fs = require("fs");
  const files = fs.readdirSync(`${process.cwd()}/content/articles`, "utf-8");
  const articles = files.filter((fn: any) => fn.endsWith(".md"));
  const data = articles.map((blog: any) => {
    const path = `${process.cwd()}/content/articles/${blog}`;
    const rawContent = fs.readFileSync(path, {
      encoding: "utf-8",
    });
    return rawContent;
  });

  return {
    props: {
      data,
    },
  };
};

After getting the data from the files you can return it to your component as props.

3.a. Template-Based

For example we’ve created multiple templates for our needs and the below is one of the templates.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import React from 'react'
import ReactMarkdown from "react-markdown";
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import { oneLight } from 'react-syntax-highlighter/dist/cjs/styles/prism';
import Image from 'next/image';
import { Stack,Typography } from '@mui/material';

export default function Template1({ articleData }: any) {
return (<>
    <Stack className="cmnflx">
        <Stack width={"100%"} sx={{ flexDirection: { xs: "column", md: "row" } }}>
            <Typography fontWeight={800} fontSize={32} className="headerTitle">
                {realData.data.title}
            </Typography>
        <Stack width={"100%"} className="cmnflx">
        <Image alt={realData.data.title} height={300} width={300} src={realData.data.featureImage || realData.data.thumbnail} />
    </Stack>
 <ReactMarkdown
    children={articleData.data.challenge}
    components={{ code({ node, inline, className, children, ...props }) {
    const match = /language-(\w+)/.exec(className || "");
        return !inline && match ? (
            <SyntaxHighlighter
                children={String(children).replace(/\n$/, "")}
                style={oneLight}
                language={match[1]}
                PreTag="div"
            />
            ) : (
                    <code className={className} {...props}>
                    {children}
                    </code>
                    );
                },
            }}
    />
    </Stack>
  </>
)
}

The ReactMarkdown is used for showing the content the same as how they are meant to be. The Prism SyntaxHighlighter is used for styles in the markdown content for codes, html tags etc., The OneLight is the theme we’ve preferred for this template.

3.b. Component-Based Architecture

Leverage the power of React components to create modular and reusable pieces of your user interface. Each template can be represented as a React component, making it easier to manage and maintain. In this example we have used one template for “Admin” and one for “User”. Based on the authentication the user will have their access and a customised user interface.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// components/Templates/AdminTemplate.js
const AdminTemplate = ({ children }) => (
  <div>
    <NavBar />
    <ControlPanel />
    <main>{children}</main>
  </div>
);

// components/Templates/UserTemplate.js
const UserTemplate = ({ children }) => (
  <div>
    <Navbar />
    <main>{children}</main>
  </div>
);

3.c. Responsive Design

Make use of CSS media queries or responsive design frameworks like Bootstrap or Material UI to adjust your UI based on different device characteristics. Like use one for desktop devices, one for mobile devices and one for tablet devices.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

// DesktopLayout.js
const DesktopLayout = ({ children }) => (

  <div className="desktop-layout">
    {children}
  </div>
);

export default DesktopLayout;

// MobileLayout.js
const MobileLayout = ({ children }) => (
  <div className="mobile-layout">
    {children}
  </div>
);

export default MobileLayout;

// withDynamicLayout.js
import React from 'react';
import { useMediaQuery } from 'react-responsive';
import DesktopLayout from './DesktopLayout';
import MobileLayout from './MobileLayout';

const withDynamicLayout = (WrappedComponent) => {
const DynamicLayout = (props) => {
const isDesktop = useMediaQuery({ minWidth: 1024 });
const isMobile = useMediaQuery({ minWidth: 420, maxWidth: 680});
if (isDesktop) {
return <DesktopLayout><WrappedComponent {...props} /></DesktopLayout>;
} else if (isMobile) {
return <MobileLayout><WrappedComponent {...props} /></MobileLayout>;
}
};
return DynamicLayout;
};
export default withDynamicLayout;

Conclusion

We can conclude by affirming that dynamic template selection is a pivotal tool in a developer’s arsenal, enabling the creation of more responsive and user-centric applications. In the ever-evolving landscape of web development, the capacity to customise user experiences through various conditions, including template variations, user roles, and responsive design strategies, is crucial. This concept of dynamic rendering forms the bedrock for developing applications that don’t just fulfil user needs but go above and beyond expectations. By adapting the user interface to different device types, developers can significantly enhance user experience and cater to a diverse audience.

Whether it’s for a content management system, an e-commerce platform, or a multifaceted web application, dynamic template choice is instrumental in elevating user experience to unprecedented levels. As developers delve into implementing dynamic templates in their projects, it’s essential to experiment with various strategies to find the one that resonates best with the application’s unique requirements.

Extending this principle, we can say that the application of template-based dynamic rendering can be further expanded. Beyond the conventional use cases, it can be integrated into more complex scenarios like interactive user interfaces, personalised user journey maps, and adaptive content delivery, unlocking new potentials in user engagement and application efficiency. This approach is not just a trend but an emerging standard in creating sophisticated, intuitive, and adaptable web applications. Happy coding!