<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>User Interface Design Archives | DMC, Inc.</title>
	<atom:link href="https://static.dmcinfo.com/blog/category/application-development/user-interface-design/feed/index.xml" rel="self" type="application/rss+xml" />
	<link></link>
	<description></description>
	<lastBuildDate>Wed, 02 Sep 2026 17:27:02 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.2</generator>

<image>
	<url>https://static.dmcinfo.com/wp-content/uploads/2025/04/site-icon-150x150.png</url>
	<title>User Interface Design Archives | DMC, Inc.</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Next.js 16 + Material UI Setup Guide for App Router + RSC: Dev Diary #2</title>
		<link>https://static.dmcinfo.com/blog/44831/material-ui-nextjs-16-app-router/</link>
		
		<dc:creator><![CDATA[Christopher Olsen]]></dc:creator>
		<pubDate>Mon, 01 Jun 2026 11:00:00 +0000</pubDate>
				<category><![CDATA[Application Development]]></category>
		<category><![CDATA[User Interface Design]]></category>
		<category><![CDATA[Next.js]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/?p=44831</guid>

					<description><![CDATA[<p>In Part 1 of this two-part series, we walked through scaffolding a brand-new React application with Next.js. The result was a bare bones application with no styling to speak of. Early in any web application project, you have an important decision to make: are you going to build the look and feel of your app [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/44831/material-ui-nextjs-16-app-router/">Next.js 16 + Material UI Setup Guide for App Router + RSC: Dev Diary #2</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">In <a href="https://static.dmcinfo.com/blog/41208/building-a-dba-dashboard-with-react-and-next-js-part-1/">Part 1</a> of this two-part series, we walked through scaffolding a brand-new React application with Next.js. The result was a bare bones application with no styling to speak of. Early in any web application project, you have an important decision to make: are you going to build the look and feel of your app from scratch with custom CSS and JavaScript, or are you going to leverage a third-party solution to achieve a more professional-looking UI than you would with a custom solution and with less development effort? Most people choose the latter, and we will too.</p>



<p class="wp-block-paragraph" style="padding-bottom:var(--wp--preset--spacing--20)">At DMC, our preferred UI library is Material UI, a component library maintained by Google. I first used Material UI nearly a decade ago, before it even reached version 1.0. Since then, the library has evolved significantly and now includes first-class support for Next.js and React Server Components. In this post, we&#8217;ll walk through how to add Material UI to a new Next.js 16 application. At the time of writing, Material UI v9.0.0 is the version in use.</p>



<h2 class="wp-block-heading" id="h-installing-the-npm-packages-for-material-ui">Installing the NPM Packages for Material UI</h2>



<p class="wp-block-paragraph">First, run the following command to install the core Material UI packages using Yarn:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">C</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>yarn add @mui/material @emotion/react @emotion/styled


</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">yarn add @mui/material @emotion/react @emotion/styled</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">The Material UI documentation recommends installing <code>@fontsource/roboto</code> to use the Roboto font in your application. However, &nbsp;at the time of writing this post, that package causes the TypeScript server in my project to crash, resulting in the loss of IntelliSense support in Visual Studio Code. Because of this, I recommend skipping that package. Later in this post, we’ll import the Roboto font using a different approach.</p>



<p class="wp-block-paragraph">Next, run the following command to install the packages required to integrate Material UI with Next.js App Router:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">C</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>yarn add @mui/material-nextjs @emotion/cache


</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">yarn add @mui/material-nextjs @emotion/cache</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"></span></code></pre></div>



<h2 class="wp-block-heading" id="h-setting-up-a-material-ui-theme" style="padding-top:var(--wp--preset--spacing--30)">Setting Up a Material UI Theme</h2>



<p class="wp-block-paragraph">One of Material UI&#8217;s most useful features is its customizable themes. Material UI includes a default theme that can be extensively customized—everything from spacing, color palettes, and even border radius can be modified based on your design sensibilities.</p>



<p class="wp-block-paragraph">For this application, we&#8217;ll primarily use the default &nbsp;Material UI theme while enabling built-in light/dark mode functionality. We can initialize the theme using the <code>createTheme()</code> function:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">C</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>// src/theme.tsx
"use client";
import { createTheme } from "@mui/material/styles";

const theme = createTheme({
  typography: {
    fontFamily: "var(--font-roboto)",
  },
  cssVariables: {
    colorSchemeSelector: "class",
  },
  colorSchemes: {
    dark: true,
  },
});

export default theme;</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">// src/theme.tsx</span></span>
<span class="line"><span style="color: #CE9178">&quot;use client&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">import { createTheme } from </span><span style="color: #CE9178">&quot;@mui/material/styles&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> theme = </span><span style="color: #DCDCAA">createTheme</span><span style="color: #D4D4D4">({</span></span>
<span class="line"><span style="color: #D4D4D4">  typography: {</span></span>
<span class="line"><span style="color: #D4D4D4">    fontFamily: </span><span style="color: #CE9178">&quot;var(--font-roboto)&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">  },</span></span>
<span class="line"><span style="color: #D4D4D4">  cssVariables: {</span></span>
<span class="line"><span style="color: #D4D4D4">    colorSchemeSelector: </span><span style="color: #CE9178">&quot;class&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">  },</span></span>
<span class="line"><span style="color: #D4D4D4">  colorSchemes: {</span></span>
<span class="line"><span style="color: #D4D4D4">    dark: </span><span style="color: #569CD6">true</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">  },</span></span>
<span class="line"><span style="color: #D4D4D4">});</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">export default theme;</span></span></code></pre></div>



<p class="wp-block-paragraph">This theme configuration does three things:</p>



<ol class="wp-block-list">
<li>Sets Roboto as the default font family for all Typography components.</li>



<li>Enables dark mode support. Light mode is enabled by default.</li>



<li>Enables CSS variables and configures the colorSchemeSelector to use CSS classes.</li>
</ol>



<p class="wp-block-paragraph">The final configuration helps prevent SSR flickering, which can occur because the server cannot detect a user’s preferred color mode during the initial render. With this setup, Material UI applies either a light or dark class to the &lt;html&gt; element on the client side and uses CSS variables to apply the appropriate theme colors. This approach provides a smoother transition between server-side rendering and client-side hydration while maintaining support for light and dark themes.</p>



<figure class="wp-block-image aligncenter size-full is-resized"><img fetchpriority="high" decoding="async" width="912" height="520" src="https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-1.png" alt="Screenshot of a JavaScript code snippet manages theme switching between light and dark modes for a webpage." class="wp-image-44851" style="width:850px" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-1.png 912w, https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-1-300x171.png 300w, https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-1-768x438.png 768w" sizes="(max-width: 912px) 100vw, 912px" /></figure>



<figure class="wp-block-image aligncenter size-full is-resized"><img decoding="async" width="1055" height="292" src="https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-2.png" alt="Image displays CSS code using the Material UI (mui) framework to style an app bar component when the application is in dark mode." class="wp-image-44852" style="aspect-ratio:3.6131774707757707;width:850px;height:auto" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-2.png 1055w, https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-2-300x83.png 300w, https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-2-1024x283.png 1024w, https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-2-768x213.png 768w" sizes="(max-width: 1055px) 100vw, 1055px" /></figure>



<h2 class="wp-block-heading" id="h-color-mode-picker" style="padding-top:var(--wp--preset--spacing--30)">Color Mode Picker</h2>



<p class="wp-block-paragraph">Speaking of color mode (light/dark), it can be nice to offer users a way to switch between light mode and dark mode. With the way we&#8217;ve configured our theme, Material UI will automatically set the color mode based on the user&#8217;s system preference, set in their web browser. So if a user has configured &#8220;dark&#8221; mode in Chrome, for example, when they visit our application, they&#8217;ll automatically get the dark-mode version of our UI.</p>



<p class="wp-block-paragraph">Some users may want dark mode specifically for our application and light mode elsewhere, so to provide that flexibility, we&#8217;ll build a simple color mode selector. For this, we&#8217;ll use the tools Material UI provides, including input and label components, along with tools for customizing them.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">C</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>// colorThemePicker.tsx
"use client";
import FormControl from "@mui/material/FormControl";
import Select, { SelectChangeEvent } from "@mui/material/Select";
import MenuItem from "@mui/material/MenuItem";
import { useColorScheme } from "@mui/material/styles";
import { FormLabel } from "@mui/material";

export default function ColorThemePicker() {
  const { mode, setMode } = useColorScheme();
  if (!mode) {
    return null;
  }
  const handleChange = (event: SelectChangeEvent) => {
    setMode(event.target.value as "system" | "light" | "dark");
  };

  return (
    &lt;FormControl
      sx={{
        display: "flex",
        flexDirection: "row",
        alignItems: "center",
        gap: 1,
      }}
    >
      &lt;FormLabel id="theme-select-label">Theme&lt;/FormLabel>
      &lt;Select
        labelId="theme-select-label"
        aria-labelledby="theme-select-label"
        id="theme-select"
        value={mode}
        label="Theme"
        onChange={handleChange}
        sx={{ minWidth: "10rem" }}
      >
        &lt;MenuItem value="system">System&lt;/MenuItem>
        &lt;MenuItem value="light">Light&lt;/MenuItem>
        &lt;MenuItem value="dark">Dark&lt;/MenuItem>
      &lt;/Select>
    &lt;/FormControl>
  );
}

</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">// colorThemePicker.tsx</span></span>
<span class="line"><span style="color: #CE9178">&quot;use client&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">import FormControl from </span><span style="color: #CE9178">&quot;@mui/material/FormControl&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">import Select, { SelectChangeEvent } from </span><span style="color: #CE9178">&quot;@mui/material/Select&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">import MenuItem from </span><span style="color: #CE9178">&quot;@mui/material/MenuItem&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">import { useColorScheme } from </span><span style="color: #CE9178">&quot;@mui/material/styles&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">import { FormLabel } from </span><span style="color: #CE9178">&quot;@mui/material&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">export default function </span><span style="color: #DCDCAA">ColorThemePicker</span><span style="color: #D4D4D4">() {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> { mode, setMode } = </span><span style="color: #DCDCAA">useColorScheme</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (!mode) {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> null;</span></span>
<span class="line"><span style="color: #D4D4D4">  }</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> handleChange = (event: SelectChangeEvent) =&gt; {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">setMode</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">event</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">target</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">value</span><span style="color: #D4D4D4"> as </span><span style="color: #CE9178">&quot;system&quot;</span><span style="color: #D4D4D4"> | </span><span style="color: #CE9178">&quot;light&quot;</span><span style="color: #D4D4D4"> | </span><span style="color: #CE9178">&quot;dark&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">  };</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> (</span></span>
<span class="line"><span style="color: #D4D4D4">    &lt;FormControl</span></span>
<span class="line"><span style="color: #D4D4D4">      sx={{</span></span>
<span class="line"><span style="color: #D4D4D4">        display: </span><span style="color: #CE9178">&quot;flex&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">        flexDirection: </span><span style="color: #CE9178">&quot;row&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">        alignItems: </span><span style="color: #CE9178">&quot;center&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">        gap: </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">      }}</span></span>
<span class="line"><span style="color: #D4D4D4">    &gt;</span></span>
<span class="line"><span style="color: #D4D4D4">      &lt;FormLabel id=</span><span style="color: #CE9178">&quot;theme-select-label&quot;</span><span style="color: #D4D4D4">&gt;Theme&lt;/FormLabel&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">      &lt;Select</span></span>
<span class="line"><span style="color: #D4D4D4">        labelId=</span><span style="color: #CE9178">&quot;theme-select-label&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">        aria-labelledby=</span><span style="color: #CE9178">&quot;theme-select-label&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">        id=</span><span style="color: #CE9178">&quot;theme-select&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">        value={mode}</span></span>
<span class="line"><span style="color: #D4D4D4">        label=</span><span style="color: #CE9178">&quot;Theme&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">        onChange={handleChange}</span></span>
<span class="line"><span style="color: #D4D4D4">        sx={{ minWidth: </span><span style="color: #CE9178">&quot;10rem&quot;</span><span style="color: #D4D4D4"> }}</span></span>
<span class="line"><span style="color: #D4D4D4">      &gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;MenuItem value=</span><span style="color: #CE9178">&quot;system&quot;</span><span style="color: #D4D4D4">&gt;System&lt;/MenuItem&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;MenuItem value=</span><span style="color: #CE9178">&quot;light&quot;</span><span style="color: #D4D4D4">&gt;Light&lt;/MenuItem&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;MenuItem value=</span><span style="color: #CE9178">&quot;dark&quot;</span><span style="color: #D4D4D4">&gt;Dark&lt;/MenuItem&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">      &lt;/Select&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">    &lt;/FormControl&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">  );</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">I&#8217;ll explain this from the top down.</p>



<p class="wp-block-paragraph">We need a piece of state to track the user&#8217;s color mode selection: light, dark, or system (whatever they&#8217;ve selected in their browser settings). We also need a <strong>setter</strong> for that state so that we can update it based on the user&#8217;s actions. For that, we use a hook provided by Material UI: <a href="https://mui.com/material-ui/customization/dark-mode/#toggling-color-mode">useColorScheme()</a>. The <code>mode</code> returned by this hook is always undefined on the first render, so we handle that with a simple falsiness check:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">C</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>if(!mode) {
  return null;
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #C586C0">if</span><span style="color: #D4D4D4">(!mode) {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> null;</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Next, we have our return statement where we declare the UI that this component should render. We&#8217;re making use of a few components from Material UI:</p>



<ul class="wp-block-list">
<li><a href="https://mui.com/material-ui/api/form-control/" target="_blank" rel="noreferrer noopener">FormControl</a></li>



<li><a href="https://mui.com/material-ui/api/form-label/" target="_blank" rel="noreferrer noopener">FormLabel</a></li>



<li><a href="https://mui.com/material-ui/react-select/" target="_blank" rel="noreferrer noopener">Select and MenuItem</a></li>
</ul>



<p class="wp-block-paragraph">The latter two are kind of self-explanatory if you have a basic background in HTML. FormControl is a nice-to-have component that manages some state related to the input element that it wraps, such as focused state, filled state, error state, required state, etc.</p>



<p class="wp-block-paragraph">Something I want to point out is the use of the sx prop on the FormControl component. This is a CSS-in-JS styling solution from Material UI, intended for one-off customization. Our application has precisely one color theme picker, so it easily fits the definition of a one-off customization. You can read more about this system in the <a href="https://mui.com/system/getting-started/usage" target="_blank" rel="noreferrer noopener">Material UI documentation</a>.</p>



<p class="wp-block-paragraph">The purpose served by our use of the <code>sx</code> prop here is to apply some flexbox CSS properties to our <code>FormControl</code> to make its child elements (the <code>FormLabel</code> and <code>Select</code> components) appear side by side instead of displaying the form label above the select component.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">C</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>&lt;FormControl
  sx={{
    display: "flex",
    flexDirection: "row",
    alignItems: "center",
    gap: 1,
  }}
>/
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">&lt;FormControl</span></span>
<span class="line"><span style="color: #D4D4D4">  sx={{</span></span>
<span class="line"><span style="color: #D4D4D4">    display: </span><span style="color: #CE9178">&quot;flex&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    flexDirection: </span><span style="color: #CE9178">&quot;row&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    alignItems: </span><span style="color: #CE9178">&quot;center&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    gap: </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">  }}</span></span>
<span class="line"><span style="color: #D4D4D4">&gt;/</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Under the hood, a CSS selector is generated and applied to the rendered DOM element, and a &lt;style&gt; tag containing the corresponding CSS rule(s) is inserted into the DOM (see the screenshot below). So the result is similar to what we would get with a style sheet, except that it is generated at runtime after the initial HTML document is served to the client, which introduces some overhead for applying style rules.</p>



<figure class="wp-block-image aligncenter size-full is-resized"><img decoding="async" width="1377" height="158" src="https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-3.png" alt="Image displaying a CSS style block generated by the Material-UI (MUI) library, specifically targeting a form label component." class="wp-image-44854" style="width:850px" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-3.png 1377w, https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-3-300x34.png 300w, https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-3-1024x117.png 1024w, https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-3-768x88.png 768w" sizes="(max-width: 1377px) 100vw, 1377px" /></figure>



<p class="wp-block-paragraph">In short, the trade-off is simpler code that&#8217;s easier to understand in exchange for a performance drop: up to 3x slower render time for 1,000 components, according to the documentation, which means you have to be rendering a lot of items to get a noticeable performance difference.</p>



<p class="wp-block-paragraph">Here&#8217;s what our color scheme picker looks like when rendered on the page:</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="274" height="227" src="https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-4.png" alt="Image displaying a drop-down menu for selecting a user interface Theme with &quot;Light&quot; selected." class="wp-image-44855" style="width:280px"/></figure>



<p class="wp-block-paragraph">And in dark mode:</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="286" height="223" src="https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-5.png" alt="Image displaying a drop-down menu for selecting a user interface Theme with &quot;Dark&quot; selected." class="wp-image-44856" style="width:280px"/></figure>



<p class="wp-block-paragraph">Not bad!</p>



<h2 class="wp-block-heading" id="h-client-components-and-building-a-nav-bar" style="padding-top:var(--wp--preset--spacing--30)">Client Components and Building a Nav Bar</h2>



<p class="wp-block-paragraph">Material UI has a <code>&lt;Link&gt;</code> component that makes it easy to render a professional-looking link on a web page. Since we&#8217;re using Next.js, we also want to use the <code>&lt;Link&gt;</code> component, which handles both server- and client-side routing. We&#8217;ll do this by providing the Next.js <code>&lt;Link&gt;</code> to the Material UI <code>&lt;Link&gt;</code> &#8220;component&#8221; prop, which essentially tells Material UI, &#8220;use this as the underlying component that you then attach all your fancy styles to.&#8221;</p>



<p class="wp-block-paragraph">However, with Next.js 16, this can result in an error: &#8220;Functions cannot be passed directly to Client Component&#8221;. As outlined in the Material UI documentation for Next.js integration, we can work around this by creating a client-side wrapper component for the Next.js <code>&lt;Link&gt;</code> component.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">C</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>// src\app\_components\link.tsx
'use client';
import Link, { LinkProps } from 'next/link';

export default Link;
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">// src\app\_components\link.tsx</span></span>
<span class="line"><span style="color: #CE9178">&apos;use client&apos;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">import Link, { LinkProps } from </span><span style="color: #CE9178">&apos;next/link&apos;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">export default Link;</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">This will come in handy when building our top nav bar for this application, which we can get started on:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">C</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>// src\app\_components\topNavBar.tsx 
import NextLink from "./link";
// (rest of import section omitted for brevity)

function TopNavBar() {
  return (
    &lt;AppBar position="static">
      &lt;Container
        maxWidth="xl"
        sx={{ display: "flex", justifyContent: "space-between" }}
      >
        &lt;Box
          sx={{
            display: "flex",
            justifyContent: "space-between",
            alignItems: "center",
          }}
          component="nav"
        >
          &lt;Link component={NextLink} href="/" color="inherit" underline="none">
            &lt;Typography
              variant="body1"
              component="span"
              sx={{ display: "flex", alignItems: "center", gap: 0.5 }}
            >
              &lt;Icon>home&lt;/Icon>
              Home
            &lt;/Typography>
          &lt;/Link>
        &lt;/Box>
        &lt;ColorThemePicker />
      &lt;/Container>
    &lt;/AppBar>
  );
}

export default TopNavBar;
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">// src\app\_components\topNavBar.tsx </span></span>
<span class="line"><span style="color: #D4D4D4">import NextLink from </span><span style="color: #CE9178">&quot;./link&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #6A9955">// (rest of import section omitted for brevity)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">function </span><span style="color: #DCDCAA">TopNavBar</span><span style="color: #D4D4D4">() {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> (</span></span>
<span class="line"><span style="color: #D4D4D4">    &lt;AppBar position=</span><span style="color: #CE9178">&quot;static&quot;</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">      &lt;Container</span></span>
<span class="line"><span style="color: #D4D4D4">        maxWidth=</span><span style="color: #CE9178">&quot;xl&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">        sx={{ display: </span><span style="color: #CE9178">&quot;flex&quot;</span><span style="color: #D4D4D4">, justifyContent: </span><span style="color: #CE9178">&quot;space-between&quot;</span><span style="color: #D4D4D4"> }}</span></span>
<span class="line"><span style="color: #D4D4D4">      &gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;Box</span></span>
<span class="line"><span style="color: #D4D4D4">          sx={{</span></span>
<span class="line"><span style="color: #D4D4D4">            display: </span><span style="color: #CE9178">&quot;flex&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">            justifyContent: </span><span style="color: #CE9178">&quot;space-between&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">            alignItems: </span><span style="color: #CE9178">&quot;center&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">          }}</span></span>
<span class="line"><span style="color: #D4D4D4">          component=</span><span style="color: #CE9178">&quot;nav&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">        &gt;</span></span>
<span class="line"><span style="color: #D4D4D4">          &lt;Link component={NextLink} href=</span><span style="color: #CE9178">&quot;/&quot;</span><span style="color: #D4D4D4"> color=</span><span style="color: #CE9178">&quot;inherit&quot;</span><span style="color: #D4D4D4"> underline=</span><span style="color: #CE9178">&quot;none&quot;</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">            &lt;Typography</span></span>
<span class="line"><span style="color: #D4D4D4">              variant=</span><span style="color: #CE9178">&quot;body1&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">              component=</span><span style="color: #CE9178">&quot;span&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">              sx={{ display: </span><span style="color: #CE9178">&quot;flex&quot;</span><span style="color: #D4D4D4">, alignItems: </span><span style="color: #CE9178">&quot;center&quot;</span><span style="color: #D4D4D4">, gap: </span><span style="color: #B5CEA8">0.5</span><span style="color: #D4D4D4"> }}</span></span>
<span class="line"><span style="color: #D4D4D4">            &gt;</span></span>
<span class="line"><span style="color: #D4D4D4">              &lt;Icon&gt;home&lt;/Icon&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">              Home</span></span>
<span class="line"><span style="color: #D4D4D4">            &lt;/Typography&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">          &lt;/Link&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;/Box&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;ColorThemePicker /&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">      &lt;/Container&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">    &lt;/AppBar&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">  );</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">export default TopNavBar;</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">For our top nav bar, we&#8217;re using the <a href="https://mui.com/material-ui/react-app-bar" target="_blank" rel="noreferrer noopener">AppBar</a> component from Material UI. This component looks great at the top of the screen and is an ideal place for top-level links, action buttons, menus, a login/logout button, etc.</p>



<p class="wp-block-paragraph">We&#8217;re putting a couple of elements into our top nav bar to start out:</p>



<ol class="wp-block-list">
<li>A list of links (currently just a link to the home page)</li>



<li>The color theme picker (this will eventually be replaced with a &#8220;hamburger button&#8221; that opens a modal dialog with settings/options)</li>
</ol>



<p class="wp-block-paragraph">I want these two components to be evenly spaced across the app bar, which sounds like a job for flexbox. To make that happen, I need to wrap them in a component, and <a href="https://mui.com/material-ui/react-container" target="_blank" rel="noreferrer noopener">Material UI&#8217;s Container</a> component fits the bill. I&#8217;m using Container because it&#8217;s a responsive component—we can use the <code>maxWidth</code> prop to define how <em>wide</em> it&#8217;s allowed to get based on the screen size. I want this nav bar to resize responsively all the way up to large desktop screens, so I&#8217;m providing &#8220;xl&#8221; as the value here &#8211; the width of the container will automatically adjust to smaller screen sizes.</p>



<p class="wp-block-paragraph">We can use the <code>sx</code> prop here to provide custom styling rules for this component—in this case, that would be using the &#8220;display&#8221; and &#8220;justifyContent&#8221; CSS properties to declare that the children of this component should be spaced evenly across the width of this container.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">C</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>&lt;Container
  maxWidth="xl"
  sx={{ display: "flex", justifyContent: "space-between" }}
>
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">&lt;Container</span></span>
<span class="line"><span style="color: #D4D4D4">  maxWidth=</span><span style="color: #CE9178">&quot;xl&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">  sx={{ display: </span><span style="color: #CE9178">&quot;flex&quot;</span><span style="color: #D4D4D4">, justifyContent: </span><span style="color: #CE9178">&quot;space-between&quot;</span><span style="color: #D4D4D4"> }}</span></span>
<span class="line"><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">To follow HTML best practices, we want to wrap our navigation links in a semantic <code>&lt;nav&gt;</code> element. But we also want to make sure that the links themselves are evenly spaced, so we need to apply some CSS rules to this <code>&lt;nav&gt;</code> element. The best way to accomplish this with Material UI is to use the generic <a href="https://mui.com/material-ui/react-box/" target="_blank" rel="noreferrer noopener">Box</a> component.</p>



<p class="wp-block-paragraph">Whenever you need to wrap other components with a containing element and apply style rules to it, <code>&lt;Box&gt;</code> is the go-to component. And we can tell Material UI which HTML element to render in the DOM by using the component prop, so we&#8217;ll pass the value &#8220;nav&#8221; to that prop to ensure it renders as a proper nav element. And again, we&#8217;re using the sx prop to define some basic flexbox properties and ensure that our link elements inside this box are spaced evenly and positioned nicely.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">C</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>&lt;Box
  sx={{
    display: "flex",
    justifyContent: "space-between",
    alignItems: "center",
  }}
  component="nav"
>
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">&lt;Box</span></span>
<span class="line"><span style="color: #D4D4D4">  sx={{</span></span>
<span class="line"><span style="color: #D4D4D4">    display: </span><span style="color: #CE9178">&quot;flex&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    justifyContent: </span><span style="color: #CE9178">&quot;space-between&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    alignItems: </span><span style="color: #CE9178">&quot;center&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">  }}</span></span>
<span class="line"><span style="color: #D4D4D4">  component=</span><span style="color: #CE9178">&quot;nav&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">To start with, we&#8217;re going to only have one link in our nav bar: &#8220;Home&#8221;. The simplest version of this would just be to use Material UI&#8217;s Link component, pass my wrapper for the Next.js Link to the &#8220;component&#8221; prop, and, of course, set href to &#8220;/&#8221;. Like the following:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">C</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>&lt;Link component={NextLink} href="/" color="inherit" underline="none">
  Home
&lt;/Link>
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">&lt;Link component={NextLink} href=</span><span style="color: #CE9178">&quot;/&quot;</span><span style="color: #D4D4D4"> color=</span><span style="color: #CE9178">&quot;inherit&quot;</span><span style="color: #D4D4D4"> underline=</span><span style="color: #CE9178">&quot;none&quot;</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">  Home</span></span>
<span class="line"><span style="color: #D4D4D4">&lt;/Link&gt;</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">But I also want to add a nifty little house icon to this link. Because I want this link to be inviting: &#8220;Come on home, you&#8217;re tired, and we have a nice fire going. You can take off your socks and cozy up by the fireplace with some hot cocoa and a grilled cheese sandwich.&#8221;</p>



<p class="wp-block-paragraph">Material UI makes that easy with its <a href="https://mui.com/material-ui/icons/" target="_blank" rel="noreferrer noopener">Icon</a> component. You can choose SVG or Font for the icons. To get off to a quick and easy start, I recommend the Font option. Later in this post, I&#8217;ll show how to enable that, but here&#8217;s what it&#8217;s going to look like in this component:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">C</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>&lt;Link component={NextLink} href="/" color="inherit" underline="none">
  &lt;Icon>home&lt;/Icon>
  Home
&lt;/Link>
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">&lt;Link component={NextLink} href=</span><span style="color: #CE9178">&quot;/&quot;</span><span style="color: #D4D4D4"> color=</span><span style="color: #CE9178">&quot;inherit&quot;</span><span style="color: #D4D4D4"> underline=</span><span style="color: #CE9178">&quot;none&quot;</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">  &lt;Icon&gt;home&lt;/Icon&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">  Home</span></span>
<span class="line"><span style="color: #D4D4D4">&lt;/Link&gt;</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">This ends up looking like the following when rendered on the page:</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="188" height="74" src="https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-6.png" alt="Screenshot of &quot;home&quot; link and &quot;home&quot; icon. The icon is positioned awkwardly off-center, making it look crooked." class="wp-image-44860" style="aspect-ratio:2.540772532188841;width:175px;height:auto"/></figure>



<p class="wp-block-paragraph">Oops! That icon is crooked! Or more accurately, it&#8217;s not vertically centered, so it looks awkward next to the text &#8220;Home&#8221;. We&#8217;ll fix that by applying some flexbox styling to the Link component:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">C</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>&lt;Link
  component={NextLink}
  href="/"
  color="inherit"
  underline="none"
  sx={{ display: "flex", alignItems: "center", gap: "0.5rem" }}
>
  &lt;Icon>home&lt;/Icon>
  Home
&lt;/Link>
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">&lt;Link</span></span>
<span class="line"><span style="color: #D4D4D4">  component={NextLink}</span></span>
<span class="line"><span style="color: #D4D4D4">  href=</span><span style="color: #CE9178">&quot;/&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">  color=</span><span style="color: #CE9178">&quot;inherit&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">  underline=</span><span style="color: #CE9178">&quot;none&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">  sx={{ display: </span><span style="color: #CE9178">&quot;flex&quot;</span><span style="color: #D4D4D4">, alignItems: </span><span style="color: #CE9178">&quot;center&quot;</span><span style="color: #D4D4D4">, gap: </span><span style="color: #CE9178">&quot;0.5rem&quot;</span><span style="color: #D4D4D4"> }}</span></span>
<span class="line"><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">  &lt;Icon&gt;home&lt;/Icon&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">  Home</span></span>
<span class="line"><span style="color: #D4D4D4">&lt;/Link&gt;</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">The result looks so much better!</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="131" height="58" src="https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-7.png" alt="Screenshot of &quot;home&quot; link and &quot;home icon&quot;, vertically aligned to look neater." class="wp-image-44861" style="aspect-ratio:2.2589298319920936;object-fit:cover;width:175px"/></figure>



<p class="wp-block-paragraph">Finally, after the nav links themselves, we have the color theme picker. Altogether, our nav bar looks like the following screenshot:</p>



<figure class="wp-block-image aligncenter size-full"><img decoding="async" width="1230" height="232" src="https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-8.png" alt="Screenshot of top nav bar." class="wp-image-44863" style="aspect-ratio:5.30214424951267" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-8.png 1230w, https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-8-300x57.png 300w, https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-8-1024x193.png 1024w, https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-8-768x145.png 768w" sizes="(max-width: 1230px) 100vw, 1230px" /></figure>



<p class="wp-block-paragraph">Not bad, at least to start.</p>



<h2 class="wp-block-heading" id="h-updating-the-root-layout" style="padding-top:var(--wp--preset--spacing--30)">Updating the Root Layout</h2>



<p class="wp-block-paragraph">Now we&#8217;re ready to update our root layout (/src/app/layout.tsx) to use Material UI in our application.</p>



<h3 class="wp-block-heading" id="h-roboto-font-set-up" style="padding-top:var(--wp--preset--spacing--30)">Roboto Font Set Up</h3>



<p class="wp-block-paragraph">To enable using the Roboto font as the default font for our app, we need to use <a href="https://nextjs.org/docs/app/getting-started/fonts" target="_blank" rel="noreferrer noopener">Next.js font optimization</a>. The result of this step is that we end up self-hosting the Roboto font from Google:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">C</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>const roboto = Roboto({
  weight: &#91;"300", "400", "500", "700"&#93;,
  subsets: &#91;"latin"&#93;,
  display: "swap",
  variable: "--font-roboto",
});
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> roboto = </span><span style="color: #DCDCAA">Roboto</span><span style="color: #D4D4D4">({</span></span>
<span class="line"><span style="color: #D4D4D4">  weight: &#91;</span><span style="color: #CE9178">&quot;300&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;400&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;500&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;700&quot;</span><span style="color: #D4D4D4">&#93;,</span></span>
<span class="line"><span style="color: #D4D4D4">  subsets: &#91;</span><span style="color: #CE9178">&quot;latin&quot;</span><span style="color: #D4D4D4">&#93;,</span></span>
<span class="line"><span style="color: #D4D4D4">  display: </span><span style="color: #CE9178">&quot;swap&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">  variable: </span><span style="color: #CE9178">&quot;--font-roboto&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">});</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">With that set up, we can give our HTML (root) element a new CSS class that will help give every typography element the Roboto font:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">C</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>&lt;html lang="en" className={roboto.variable} suppressHydrationWarning>

</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">&lt;html lang=</span><span style="color: #CE9178">&quot;en&quot;</span><span style="color: #D4D4D4"> className={</span><span style="color: #9CDCFE">roboto</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">variable</span><span style="color: #D4D4D4">} suppressHydrationWarning&gt;</span></span>
<span class="line"></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Remember how we set up our theme with the following property?</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">C</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>typography: {
  fontFamily: "var(--font-roboto)",
},
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">typography: {</span></span>
<span class="line"><span style="color: #D4D4D4">  fontFamily: </span><span style="color: #CE9178">&quot;var(--font-roboto)&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">},</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">That &#8220;var(&#8211;font-roboto)&#8221; element is a <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Cascading_variables/Using_custom_properties" target="_blank" rel="noreferrer noopener">CSS variable</a>. When combined, these two things result in a CSS variable named &#8220;&#8211;font-roboto&#8221; that&#8217;s <em>scoped</em> to a CSS class that&#8217;s generated at runtime and inserted into the stylesheet. This CSS class is then assigned to the <code>&lt;html&gt;</code> element so that any element in our HTML document can use that CSS variable. And by utilizing the &#8220;fontFamily&#8221; property of the &#8220;typography&#8221; section of our theme, we ensure that every typography element (MUI or not) uses the value of that variable for its &#8220;font-family&#8221; CSS property.</p>



<p class="wp-block-paragraph">The following screenshots from Chrome dev tools demonstrate this in action:</p>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="816" height="67" src="https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-9.png" alt="HTML tag showing the dynamically-generated CSS class." class="wp-image-44875" style="width:850px" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-9.png 816w, https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-9-300x25.png 300w, https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-9-768x63.png 768w" sizes="(max-width: 816px) 100vw, 816px" /></figure>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="552" height="101" src="https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-10.png" alt="Screenshot showing the CSS variable &quot;--font-roboto&quot;" class="wp-image-44877" style="width:500px" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-10.png 552w, https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-10-300x55.png 300w" sizes="(max-width: 552px) 100vw, 552px" /></figure>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="543" height="234" src="https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-11.png" alt="Screenshot of a CSS rule for a label component, with the &quot;font-family&quot; property set to &quot;var(--font-roboto)&quot;" class="wp-image-44878" style="width:500px" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-11.png 543w, https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-11-300x129.png 300w" sizes="(max-width: 543px) 100vw, 543px" /></figure>



<h3 class="wp-block-heading" id="h-material-icons-set-up" style="padding-top:var(--wp--preset--spacing--40)">Material Icons Set Up</h3>



<p class="wp-block-paragraph">We need to import the Material Icons font so that we can use icons in our app. The easiest way to do this is to get it from the CDN. We can use the <code>&lt;head&gt;</code> element in our root layout.tsx file to insert a stylesheet link into the HTML document, ensuring that the user&#8217;s browser downloads that font.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">C</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>&lt;head>
  &lt;link
    rel="stylesheet"
    href="https://fonts.googleapis.com/icon?family=Material+Icons"
  />
&lt;/head>
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">&lt;head&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">  &lt;link</span></span>
<span class="line"><span style="color: #D4D4D4">    rel=</span><span style="color: #CE9178">&quot;stylesheet&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">    href=</span><span style="color: #CE9178">&quot;https://fonts.googleapis.com/icon?family=Material+Icons&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">  /&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">&lt;/head&gt;</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">There&#8217;s also an NPM package you can install to self-host the font, but as I said earlier, it seems to crash the TypeScript server when using Next.js 16, so we&#8217;ll use the CDN until that gets sorted out.</p>



<h3 class="wp-block-heading" id="h-approutercacheprovider" style="padding-top:var(--wp--preset--spacing--30)">AppRouterCacheProvider</h3>



<p class="wp-block-paragraph">For optimal performance, it&#8217;s best to wrap your application with Material UI&#8217;s AppRouterCacheProvider component. According to the <a href="https://mui.com/material-ui/integrations/nextjs/#configuration" target="_blank" rel="noreferrer noopener">documentation</a>, this component &#8220;is responsible for collecting the CSS generated by MUI System on the server, as Next.js is streaming chunks of the .html page to the client.&#8221;</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">C</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>&lt;body>
  &lt;AppRouterCacheProvider>
    &lt;main>
      {children}
    &lt;/main>
  &lt;/AppRouterCacheProvider>
&lt;/body>
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">&lt;body&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">  &lt;AppRouterCacheProvider&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">    &lt;main&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">      {children}</span></span>
<span class="line"><span style="color: #D4D4D4">    &lt;/main&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">  &lt;/AppRouterCacheProvider&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">&lt;/body&gt;</span></span>
<span class="line"></span></code></pre></div>



<h3 class="wp-block-heading" id="h-themeprovider" style="padding-top:var(--wp--preset--spacing--30)">ThemeProvider</h3>



<p class="wp-block-paragraph">For our application to use our custom theme, we need to wrap our application with the ThemeProvider component from Material UI, and provide our custom theme to the &#8220;theme&#8221; prop:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">C</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>import theme from "../theme";
// ...
&lt;body>
  &lt;AppRouterCacheProvider>
    &lt;ThemeProvider theme={theme}>
      &lt;main>
        {children}
      &lt;/main>
    &lt;/ThemeProvider>
  &lt;/AppRouterCacheProvider>
&lt;/body>
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">import theme from </span><span style="color: #CE9178">&quot;../theme&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #6A9955">// ...</span></span>
<span class="line"><span style="color: #D4D4D4">&lt;body&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">  &lt;AppRouterCacheProvider&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">    &lt;ThemeProvider theme={theme}&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">      &lt;main&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        {children}</span></span>
<span class="line"><span style="color: #D4D4D4">      &lt;/main&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">    &lt;/ThemeProvider&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">  &lt;/AppRouterCacheProvider&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">&lt;/body&gt;</span></span>
<span class="line"></span></code></pre></div>



<h3 class="wp-block-heading" id="h-cssbaseline" style="padding-top:var(--wp--preset--spacing--30)">CssBaseline</h3>



<p class="wp-block-paragraph">The <a href="https://mui.com/material-ui/react-css-baseline" target="_blank" rel="noreferrer noopener">CssBaseline</a> component allows us to clear out some undesirable CSS rules that browsers tend to have enabled by default. For example, without this component, there would be a default &#8220;margin&#8221; rule for <code>&lt;html&gt;</code> and <code>&lt;body&gt;</code>, resulting in a space around our actual page. So, our AppBar would not stretch all the way to the edges of the page, which is a jarring look. See the following screenshot for an example of what that looks like:</p>



<figure class="wp-block-image size-full is-resized has-custom-border"><img decoding="async" width="426" height="242" src="https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-12-1.png" alt="Screenshot of the margin that appears by default if CssBaseline isn't used." class="has-border-color has-custom-black-border-color wp-image-44882" style="border-width:1px;aspect-ratio:1.7553438063353077;object-fit:cover;width:500px" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-12-1.png 426w, https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-12-1-300x170.png 300w" sizes="(max-width: 426px) 100vw, 426px" /></figure>



<p class="wp-block-paragraph">So to avoid this, we simply have to add the CssBaseline component to our root layout:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">C</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>&lt;body>
  &lt;AppRouterCacheProvider>
    &lt;ThemeProvider theme={theme}>
      &lt;CssBaseline />
      &lt;main>
        {children}
      &lt;/main>
    &lt;/ThemeProvider>
  &lt;/AppRouterCacheProvider>
&lt;/body>
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">&lt;body&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">  &lt;AppRouterCacheProvider&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">    &lt;ThemeProvider theme={theme}&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">      &lt;CssBaseline /&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">      &lt;main&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        {children}</span></span>
<span class="line"><span style="color: #D4D4D4">      &lt;/main&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">    &lt;/ThemeProvider&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">  &lt;/AppRouterCacheProvider&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">&lt;/body&gt;</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">That makes the margin disappear, as we can see in this screenshot:</p>



<figure class="wp-block-image size-full is-resized has-custom-border"><img decoding="async" width="387" height="224" src="https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-13.png" alt="Screenshot of app without the browser default margin, thanks to CssBaseline." class="has-border-color has-custom-black-border-color wp-image-44883" style="border-width:1px;width:500px" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-13.png 387w, https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-13-300x174.png 300w" sizes="(max-width: 387px) 100vw, 387px" /></figure>



<h3 class="wp-block-heading" id="h-initcolorschemescript" style="padding-top:var(--wp--preset--spacing--30)">InitColorSchemeScript</h3>



<p class="wp-block-paragraph">The <a href="https://mui.com/material-ui/react-init-color-scheme-script/#introduction" target="_blank" rel="noreferrer noopener">InitColorSchemeScript</a> component, when rendered before any of our actual content, will cause a script to run that attaches an attribute (a CSS class in our case) to the <code>&lt;html&gt;</code> element, indicating whether to use light or dark mode, depending on user preference. This runs <em>before</em> React itself starts doing client-side rendering and hydration; the result is that we prevent a &#8220;flicker&#8221; that would otherwise occur because the color scheme is not the default that&#8217;s assumed during server-side render.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">C</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>&lt;body>
  &lt;AppRouterCacheProvider>
    &lt;ThemeProvider theme={theme}>
      &lt;CssBaseline />
      &lt;InitColorSchemeScript attribute="class" />
      &lt;main>
        {children}
      &lt;/main>
    &lt;/ThemeProvider>
  &lt;/AppRouterCacheProvider>
&lt;/body>
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">&lt;body&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">  &lt;AppRouterCacheProvider&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">    &lt;ThemeProvider theme={theme}&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">      &lt;CssBaseline /&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">      &lt;InitColorSchemeScript attribute=</span><span style="color: #CE9178">&quot;class&quot;</span><span style="color: #D4D4D4"> /&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">      &lt;main&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        {children}</span></span>
<span class="line"><span style="color: #D4D4D4">      &lt;/main&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">    &lt;/ThemeProvider&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">  &lt;/AppRouterCacheProvider&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">&lt;/body&gt;</span></span>
<span class="line"></span></code></pre></div>



<h3 class="wp-block-heading" id="h-wrapping-app-contents-in-a-container-and-adding-the-nav-bar" style="padding-top:var(--wp--preset--spacing--30)">Wrapping App Contents in a Container and Adding the Nav Bar</h3>



<p class="wp-block-paragraph">To finish things up here, we&#8217;re going to wrap the child components (i.e., the contents of any given page) in a Container component so that they appear to be the same width as the content of our AppBar. Without this, the content of the app&#8217;s pages would stretch to the edge of the screen. See the following screenshot—it doesn&#8217;t look right.</p>



<figure class="wp-block-image size-full is-resized has-custom-border"><img decoding="async" width="470" height="212" src="https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-14.png" alt="Screenshot of the web page's content stretching all the way to the edge of the browser window, making it wider than the nav bar's contents." class="has-border-color has-custom-black-border-color wp-image-44886" style="border-width:1px;width:500px" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-14.png 470w, https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-14-300x135.png 300w" sizes="(max-width: 470px) 100vw, 470px" /></figure>



<p class="wp-block-paragraph">By wrapping <code>{children}</code> in a container and giving it <code>maxWidth</code> of &#8220;xl&#8221;, matching the approach used for the AppBar content, we ensure the entire application aligns cleanly and maintains a comfortable margin between the screen edge and the app’s content.</p>



<figure class="wp-block-image size-full is-resized has-custom-border"><img decoding="async" width="543" height="220" src="https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-15.png" alt="Screenshot of the web page's content having the same margin from the edge of the screen as the nav bar's contents." class="has-border-color has-custom-black-border-color wp-image-44889" style="border-width:1px;width:500px" srcset="https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-15.png 543w, https://static.dmcinfo.com/wp-content/uploads/2026/05/adding-material-ui-next.js-image-15-300x122.png 300w" sizes="(max-width: 543px) 100vw, 543px" /></figure>



<p class="wp-block-paragraph">We&#8217;ll also render our custom TopNavBar component <em>before</em> the container, so that the nav bar always appears at the top of the page, with the current web page being displayed beneath it.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">C</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>&lt;body>
  &lt;AppRouterCacheProvider>
    &lt;ThemeProvider theme={theme}>
      &lt;CssBaseline />
      &lt;InitColorSchemeScript attribute="class" />
      &lt;main>
        &lt;TopNavBar />
        &lt;Container maxWidth="xl">{children}&lt;/Container>
      &lt;/main>
    &lt;/ThemeProvider>
  &lt;/AppRouterCacheProvider>
&lt;/body>
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">&lt;body&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">  &lt;AppRouterCacheProvider&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">    &lt;ThemeProvider theme={theme}&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">      &lt;CssBaseline /&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">      &lt;InitColorSchemeScript attribute=</span><span style="color: #CE9178">&quot;class&quot;</span><span style="color: #D4D4D4"> /&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">      &lt;main&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;TopNavBar /&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;Container maxWidth=</span><span style="color: #CE9178">&quot;xl&quot;</span><span style="color: #D4D4D4">&gt;{children}&lt;/Container&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">      &lt;/main&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">    &lt;/ThemeProvider&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">  &lt;/AppRouterCacheProvider&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">&lt;/body&gt;</span></span>
<span class="line"></span></code></pre></div>



<h3 class="wp-block-heading" id="h-the-full-layout-tsx-file" style="padding-top:var(--wp--preset--spacing--30)">The Full layout.tsx File</h3>



<p class="wp-block-paragraph">Altogether, our layout.tsx file looks like this:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">C</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>// src\app\layout.tsx
import type { Metadata } from "next";
import { AppRouterCacheProvider } from "@mui/material-nextjs/v15-appRouter";
import { Roboto } from "next/font/google";
import { ThemeProvider } from "@mui/material/styles";
import theme from "../theme";
import { Container, CssBaseline, InitColorSchemeScript } from "@mui/material";
import TopNavBar from "./_components/topNavBar";

const roboto = Roboto({
  weight: &#91;"300", "400", "500", "700"&#93;,
  subsets: &#91;"latin"&#93;,
  display: "swap",
  variable: "--font-roboto",
});

export const metadata: Metadata = {
  title: "DBA Dashboard",
  description:
    "A dashboard UI for exploring the results from the SQL Server First Responder Kit stored procedures",
};

export default function RootLayout({
  children,
}: Readonly&lt;{
  children: React.ReactNode;
}>) {
  return (
    &lt;html lang="en" className={roboto.variable} suppressHydrationWarning>
      &lt;head>
        &lt;link
          rel="stylesheet"
          href="https://fonts.googleapis.com/icon?family=Material+Icons"
        />
      &lt;/head>
      &lt;body>
        &lt;AppRouterCacheProvider>
          &lt;ThemeProvider theme={theme}>
            &lt;CssBaseline />
            &lt;InitColorSchemeScript attribute="class" />
            &lt;main>
              &lt;TopNavBar />
              &lt;Container maxWidth="xl">{children}&lt;/Container>
            &lt;/main>
          &lt;/ThemeProvider>
        &lt;/AppRouterCacheProvider>
      &lt;/body>
    &lt;/html>
  );
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">// src\app\layout.tsx</span></span>
<span class="line"><span style="color: #D4D4D4">import type { Metadata } from </span><span style="color: #CE9178">&quot;next&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">import { AppRouterCacheProvider } from </span><span style="color: #CE9178">&quot;@mui/material-nextjs/v15-appRouter&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">import { Roboto } from </span><span style="color: #CE9178">&quot;next/font/google&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">import { ThemeProvider } from </span><span style="color: #CE9178">&quot;@mui/material/styles&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">import theme from </span><span style="color: #CE9178">&quot;../theme&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">import { Container, CssBaseline, InitColorSchemeScript } from </span><span style="color: #CE9178">&quot;@mui/material&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">import TopNavBar from </span><span style="color: #CE9178">&quot;./_components/topNavBar&quot;</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> roboto = </span><span style="color: #DCDCAA">Roboto</span><span style="color: #D4D4D4">({</span></span>
<span class="line"><span style="color: #D4D4D4">  weight: &#91;</span><span style="color: #CE9178">&quot;300&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;400&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;500&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;700&quot;</span><span style="color: #D4D4D4">&#93;,</span></span>
<span class="line"><span style="color: #D4D4D4">  subsets: &#91;</span><span style="color: #CE9178">&quot;latin&quot;</span><span style="color: #D4D4D4">&#93;,</span></span>
<span class="line"><span style="color: #D4D4D4">  display: </span><span style="color: #CE9178">&quot;swap&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">  variable: </span><span style="color: #CE9178">&quot;--font-roboto&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">});</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">export </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> metadata: Metadata = {</span></span>
<span class="line"><span style="color: #D4D4D4">  title: </span><span style="color: #CE9178">&quot;DBA Dashboard&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">  description:</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #CE9178">&quot;A dashboard UI for exploring the results from the SQL Server First Responder Kit stored procedures&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">};</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">export default function </span><span style="color: #DCDCAA">RootLayout</span><span style="color: #D4D4D4">({</span></span>
<span class="line"><span style="color: #D4D4D4">  children,</span></span>
<span class="line"><span style="color: #D4D4D4">}: Readonly&lt;{</span></span>
<span class="line"><span style="color: #D4D4D4">  children: </span><span style="color: #9CDCFE">React</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">ReactNode</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">}&gt;) {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> (</span></span>
<span class="line"><span style="color: #D4D4D4">    &lt;html lang=</span><span style="color: #CE9178">&quot;en&quot;</span><span style="color: #D4D4D4"> className={</span><span style="color: #9CDCFE">roboto</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">variable</span><span style="color: #D4D4D4">} suppressHydrationWarning&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">      &lt;head&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;link</span></span>
<span class="line"><span style="color: #D4D4D4">          rel=</span><span style="color: #CE9178">&quot;stylesheet&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">          href=</span><span style="color: #CE9178">&quot;https://fonts.googleapis.com/icon?family=Material+Icons&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">        /&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">      &lt;/head&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">      &lt;body&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;AppRouterCacheProvider&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">          &lt;ThemeProvider theme={theme}&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">            &lt;CssBaseline /&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">            &lt;InitColorSchemeScript attribute=</span><span style="color: #CE9178">&quot;class&quot;</span><span style="color: #D4D4D4"> /&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">            &lt;main&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">              &lt;TopNavBar /&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">              &lt;Container maxWidth=</span><span style="color: #CE9178">&quot;xl&quot;</span><span style="color: #D4D4D4">&gt;{children}&lt;/Container&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">            &lt;/main&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">          &lt;/ThemeProvider&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;/AppRouterCacheProvider&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">      &lt;/body&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">    &lt;/html&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">  );</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">We can also adjust the page.tsx (home page) component to be a bit more minimal, since it no longer needs to render its own <code>&lt;main&gt;</code>:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">C</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>// src\app\page.tsx
export default function Home() {
  return (
    &lt;>
      &lt;header>
        &lt;h1>DBA Dashboard&lt;/h1>
      &lt;/header>
      &lt;p>
        Welcome to the DBA Dashboard! There&apos;s not much here yet, but stay
        tuned for updates as we build out the UI for exploring the results from
        the SQL Server First Responder Kit stored procedures.
      &lt;/p>
    &lt;/>
  );
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">// src\app\page.tsx</span></span>
<span class="line"><span style="color: #D4D4D4">export default function </span><span style="color: #DCDCAA">Home</span><span style="color: #D4D4D4">() {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> (</span></span>
<span class="line"><span style="color: #D4D4D4">    &lt;&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">      &lt;header&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;h1&gt;DBA Dashboard&lt;/h1&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">      &lt;/header&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">      &lt;p&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        Welcome to the DBA Dashboard! There</span><span style="color: #CE9178">&apos;s not much here yet, but stay</span></span>
<span class="line"><span style="color: #CE9178">        tuned for updates as we build out the UI for exploring the results from</span></span>
<span class="line"><span style="color: #CE9178">        the SQL Server First Responder Kit stored procedures.</span></span>
<span class="line"><span style="color: #CE9178">      &lt;/p&gt;</span></span>
<span class="line"><span style="color: #CE9178">    &lt;/&gt;</span></span>
<span class="line"><span style="color: #CE9178">  );</span></span>
<span class="line"><span style="color: #CE9178">}</span></span>
<span class="line"></span></code></pre></div>



<h2 class="wp-block-heading" id="h-conclusion" style="padding-top:var(--wp--preset--spacing--40)">Conclusion</h2>



<p class="wp-block-paragraph" style="padding-bottom:var(--wp--preset--spacing--40)">And that&#8217;s it! We&#8217;ve successfully set up Material UI with our Next.js 16 application—going forward, we can easily make every UI element we add to the app look professional with minimal effort. In the next post, we&#8217;ll get authentication set up&nbsp;using a library called Better Auth, along with Microsoft&#8217;s Entra ID authentication service.</p>



<div class="wp-block-group alignwide has-custom-light-blue-background-color has-background is-layout-flow wp-container-core-group-is-layout-dbd34961 wp-block-group-is-layout-flow" style="border-radius:20px;margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50);padding-top:var(--wp--preset--spacing--50);padding-right:0;padding-bottom:var(--wp--preset--spacing--50);padding-left:0">
<div class="wp-block-columns alignwide are-vertically-aligned-center is-layout-flex wp-container-core-columns-is-layout-43efaee5 wp-block-columns-is-layout-flex" style="padding-right:var(--wp--preset--spacing--60);padding-left:var(--wp--preset--spacing--60)">
<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:85%">
<h3 class="wp-block-heading has-text-align-left" id="h-have-an-upcoming-project-dmc-can-help-you-take-the-next-step">Have an upcoming project? DMC can help you take the next step.</h3>



<p class="has-text-align-left wp-block-paragraph" id="h-need-help-turning-ideas-into-outcomes-automation-project-to-the-next-level-contact-us-today-to-learn-more-about-our-solutions-and-how-we-can-help-you-achieve-your-goals">Take your project to the next level with engineering solutions from DMC. Learn more about our <a href="https://static.dmcinfo.com/services/application-development/">Application Development</a> solutions or contact us to get started today!</p>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:15%">
<div class="wp-block-buttons is-horizontal is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-2236275c wp-block-buttons-is-layout-flex">
<div class="wp-block-button is-style-fill"><a class="wp-block-button__link has-base-contrast-color has-text-color has-link-color wp-element-button" href="https://static.dmcinfo.com/contact/">Contact Us</a></div>
</div>
</div>
</div>
</div>



<p class="wp-block-paragraph"></p>
<p>The post <a href="https://static.dmcinfo.com/blog/44831/material-ui-nextjs-16-app-router/">Next.js 16 + Material UI Setup Guide for App Router + RSC: Dev Diary #2</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Avalonia UI: Introduction and Initial Impression</title>
		<link>https://static.dmcinfo.com/blog/15658/avalonia-ui-introduction-and-initial-impression/</link>
		
		<dc:creator><![CDATA[DMC]]></dc:creator>
		<pubDate>Thu, 20 Feb 2025 12:01:59 +0000</pubDate>
				<category><![CDATA[Application Development]]></category>
		<category><![CDATA[User Interface Design]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/15658/avalonia-ui-introduction-and-initial-impression/</guid>

					<description><![CDATA[<p>Avalonia UI is an open-source UI framework for cross-platform, .NET applications. It is free to use under the MIT license, and it supports Windows, macOS, Linux, iOS, Android, and WebAssembly. The framework is owned by the commercial entity, AvaloniaUI OÜ, and it is maintained by a community of developers and a core team of around [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/15658/avalonia-ui-introduction-and-initial-impression/">Avalonia UI: Introduction and Initial Impression</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph"><a href="https://docs.avaloniaui.net/" target="_blank">Avalonia UI</a> is an open-source UI framework for cross-platform, .NET applications. It is free to use under the MIT license, and it supports Windows, macOS, Linux, iOS, Android, and WebAssembly. The framework is owned by the commercial entity, AvaloniaUI OÜ, and it is maintained by a community of developers and a core team of around twenty that work full-time for the company.&nbsp;</p>



<p class="wp-block-paragraph">Avalonia is a “spiritual successor” to WPF which gives developers a familiar experience. You can code in C#, F#, or XAML for Avalonia’s UI, and you can use different IDEs such as Visual Studio, Visual Studio Code, and JetBrains Rider, but JetBrains Rider is the IDE Avalonia recommends for development.&nbsp;</p>



<h2 id="h-a-brief-history-of-avalonia-ui-nbsp" class="wp-block-heading">A Brief History of Avalonia UI&nbsp;</h2>



<p class="wp-block-paragraph">Avalonia had its <a href="https://avaloniaui.net/blog/10-years-of-avalonia" target="_blank">first commit in December of 2013</a> when it was still called Perspex. Although Avalonia has been around for over a decade, it started gaining more popularity in 2020 when it joined the .NET Foundation. The partnership with .NET Foundation was short-lived though, and Avalonia <a href="https://github.com/AvaloniaUI/Avalonia/discussions/14666" target="_blank">left it in February of 2024</a>.&nbsp;</p>



<h2 id="h-avalonia-xpf-nbsp" class="wp-block-heading">Avalonia XPF&nbsp;</h2>



<p class="wp-block-paragraph">Along with the open-source, free to use, UI framework, the AvaloniaUI OÜ company also sells licenses to <a href="https://docs.avaloniaui.net/xpf/welcome" target="_blank">Avalonia XPF</a>.&nbsp;</p>



<p class="wp-block-paragraph">Avalonia XPF is a cross-platform fork of WPF, and it allows developers to “instantly” make a cross-platform version of their WPF project. It does this by leaving presentation core and presentation framework untouched so the WPF application “just works”. If the project has other Windows dependencies outside of WPF though, it may need additional massaging to migrate those features. For example, if your project only targets .NET Framework, which is Windows specific, updates will be needed to allow it to work cross-platform.&nbsp;</p>



<h2 id="h-initial-impression-nbsp" class="wp-block-heading">Initial Impression&nbsp;</h2>



<p class="wp-block-paragraph">Overall, Avalonia feels like a modern version of WPF, and it cleans up some of WPF’s quirks.&nbsp;</p>



<p class="wp-block-paragraph">If &nbsp;you are familiar with WPF, the ramp up time to Avalonia is fairly quick. The largest differences are getting used to <a href="https://docs.avaloniaui.net/docs/basics/user-interface/styling/styles" target="_blank">Avalonia’s styling</a> and learning the different UI <a href="https://docs.avaloniaui.net/docs/basics/user-interface/controls/">controls</a> and their properties.&nbsp;</p>



<p class="wp-block-paragraph">For developers that are new to both WPF and Avalonia, it’s likely that it would take about the same amount of time to learn either framework. The documentation for WPF is much more extensive since it’s been around longer, but a lot of it can also apply to Avalonia. Conversely, Avalonia has fewer resources, but the resources that are available are better organized and modernized. Here is where to find <a href="https://docs.avaloniaui.net/docs/get-started/" type="link" id="https://docs.avaloniaui.net/docs/get-started/">the documentation to get started</a> with Avalonia.&nbsp;</p>



<h2 id="h-support-nbsp" class="wp-block-heading">Support&nbsp;</h2>



<p class="wp-block-paragraph">Avalonia <a href="https://github.com/AvaloniaUI/Avalonia/releases" target="_blank">releases</a> updates consistently which can give developers peace of mind that it is maintained well. It supports .NET Framework 4.6.2+, .NET Core 2.0+, and .NET 5+.&nbsp;</p>



<p class="wp-block-paragraph">When using the Model-View-ViewModel (MVVM) pattern, Avalonia works well with the <a href="https://docs.avaloniaui.net/docs/concepts/reactiveui/" target="_blank">ReactiveUI</a> and <a href="https://www.nuget.org/packages/CommunityToolkit.Mvvm" target="_blank">MVVM Community ToolKit</a> libraries. This is great news since WPF also supports these libraries.&nbsp;</p>



<h2 id="h-ides-nbsp" class="wp-block-heading">IDEs&nbsp;</h2>



<p class="wp-block-paragraph">As a WPF developer that already has a <a href="https://visualstudio.microsoft.com/" target="_blank">Visual Studio license</a>, VS is my go-to IDE, and there is an <a href="https://marketplace.visualstudio.com/items?itemName=AvaloniaTeam.AvaloniaVS" target="_blank">Avalonia Extension for Visual Studio 2022</a>. Although this extension exists, it is a bit lackluster. It does not support the code completion nor the rich syntax highlighting for AXAML (Avalonia’s flavor of XAML) files that you would typically expect for XAML files. These deficiencies can cause a slower or less enjoyable developer experience.&nbsp;</p>



<p class="wp-block-paragraph"><img decoding="async" alt="Visual Studio Syntax Highlighting" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/visual-studio-syntax-highlighting.png"><br>
<em>Visual Studio Syntax Highlighting&nbsp;</em></p>



<p class="wp-block-paragraph">The IDE Avalonia recommends is <a href="https://www.jetbrains.com/rider/" target="_blank">JetBrains Rider</a>. Rider is free only for non-commercial use. This IDE makes programming in Avalonia much smoother as it does support code completion and syntax highlighting for AXAML. It also supports more obvious highlighting for file types, and its IntelliSense code “usages” feature finds references in both C# and AXAML files.</p>



<p class="wp-block-paragraph"><em><img decoding="async" alt="JetBrains Rider Syntax Highlighting" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/JetBrains-Rider-Syntax-Highlighting.png"><br>
JetBrains Rider Syntax Highlighting&nbsp;</em></p>



<p class="wp-block-paragraph">Unfortunately, Avalonia <a href="https://github.com/AvaloniaUI/Avalonia/discussions/14098" target="_blank">does not support hot reload</a> at all, but it does have an AXAML design previewer which is similar to the XAML Live Preview.&nbsp;</p>



<p class="wp-block-paragraph"><img decoding="async" alt="AXAML Design Preview " src="https://static.dmcinfo.com/wp-content/uploads/2025/05/AXAML-Design-Preview.png"><br>
<em>AXAML Design Preview&nbsp;</em></p>



<h2 id="h-cross-platform-demo-nbsp" class="wp-block-heading">Cross-Platform Demo&nbsp;</h2>



<p class="wp-block-paragraph">To demonstrate the look and feel of Avalonia on different platforms, I followed the Avalonia Music Store App tutorial and deployed it to a Windows and Linux operating system respectively.&nbsp;</p>



<p class="wp-block-paragraph"><em><img decoding="async" alt="Avalonia on Windows" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Avalonia-on-Windows.png"><br>
Windows&nbsp;</em></p>



<p class="wp-block-paragraph"><em><img decoding="async" alt="Avalonia on Linux" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Avalonia-on-Linux.png"><br>
Linux</em></p>



<p class="wp-block-paragraph">As you can see, the application looks consistent across different platforms thanks to Avalonia’s independent rendering. Avalonia does not rely on the native UI controls of the operating system. Instead, it draws the entire UI itself which allows for more flexibility and customization.&nbsp;</p>



<h2 id="h-takeaways-nbsp" class="wp-block-heading">Takeaways&nbsp;</h2>



<p class="wp-block-paragraph">Avalonia is a great option to have for desktop development, especially for cross-platform use cases. Avalonia’s styling features and components streamline development while also providing a similar feel to WPF. While Avalonia seems like WPF 2.0, WPF is still a strong choice for Windows platforms. WPF has a long history of development behind it and many resources available that have led it to be DMC’s standby for a long time.&nbsp;</p>



<p class="wp-block-paragraph">At DMC, we are always looking towards the future and learning new technologies to better support the wide variety of needs our customers have. We are excited to continue exploring Avalonia UI to provide expert solutions for cross-platform, desktop development.&nbsp;</p>



<div class="wp-block-group alignwide has-custom-light-blue-background-color has-background is-layout-flow wp-container-core-group-is-layout-dbd34961 wp-block-group-is-layout-flow" style="border-radius:20px;margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50);padding-top:var(--wp--preset--spacing--50);padding-right:0;padding-bottom:var(--wp--preset--spacing--50);padding-left:0">
<div class="wp-block-columns alignwide are-vertically-aligned-center is-layout-flex wp-container-core-columns-is-layout-43efaee5 wp-block-columns-is-layout-flex" style="padding-right:var(--wp--preset--spacing--60);padding-left:var(--wp--preset--spacing--60)">
<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:85%">
<h3 class="wp-block-heading has-text-align-left" id="h-have-an-upcoming-project-dmc-can-help-you-take-the-next-step"><strong>Need a custom .NET solution that runs across multiple platforms?</strong></h3>



<p class="has-text-align-left wp-block-paragraph" id="h-need-help-turning-ideas-into-outcomes-automation-project-to-the-next-level-contact-us-today-to-learn-more-about-our-solutions-and-how-we-can-help-you-achieve-your-goals">Build modern cross-platform applications with <a href="https://static.dmcinfo.com/services/application-development/desktop-application-development/" id="680">Avalonia UI</a>, and explore more about DMC&#8217;s <a href="https://static.dmcinfo.com/services/embedded-development-and-embedded-programming/" id="431">Embedded</a> capabilities for your software development needs.</p>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:15%">
<div class="wp-block-buttons is-horizontal is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-2236275c wp-block-buttons-is-layout-flex">
<div class="wp-block-button is-style-fill"><a class="wp-block-button__link has-base-contrast-color has-text-color has-link-color wp-element-button" href="https://static.dmcinfo.com/contact/">Contact Us</a></div>
</div>
</div>
</div>
</div>
<p>The post <a href="https://static.dmcinfo.com/blog/15658/avalonia-ui-introduction-and-initial-impression/">Avalonia UI: Introduction and Initial Impression</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Custom Image Provider Implementation in PySide</title>
		<link>https://static.dmcinfo.com/blog/17084/custom-image-provider-implementation-in-pyside/</link>
		
		<dc:creator><![CDATA[DMC]]></dc:creator>
		<pubDate>Thu, 02 Nov 2023 14:34:05 +0000</pubDate>
				<category><![CDATA[Application Development]]></category>
		<category><![CDATA[PC Application Development]]></category>
		<category><![CDATA[User Interface Design]]></category>
		<category><![CDATA[Computer Vision]]></category>
		<category><![CDATA[GUI]]></category>
		<category><![CDATA[image rendering]]></category>
		<category><![CDATA[UI]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/17084/custom-image-provider-implementation-in-pyside/</guid>

					<description><![CDATA[<p>Introduction In application development, projects require various depths of involvement. Some projects may need you to interconnect a bunch of trendy frameworks and open-source libraries, while other projects will require full-scale development in a lesser-known framework not even designed for the task at hand. A framework that is particularly interesting to work with that occasionally [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/17084/custom-image-provider-implementation-in-pyside/">Custom Image Provider Implementation in PySide</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 id="h-introduction" class="wp-block-heading">Introduction</h2>



<p class="wp-block-paragraph">In application development, projects require various depths of involvement. Some projects may need you to interconnect a bunch of trendy frameworks and open-source libraries, while other projects will require full-scale development in a lesser-known framework not even designed for the task at hand. A framework that is particularly interesting to work with that occasionally lacks proper documentation is PySide.</p>



<p class="wp-block-paragraph">I’ve had an opportunity to explore some image rendering capabilities of the framework and would like to share some tips and best practice standards for your custom application.</p>



<h2 id="h-image-provider" class="wp-block-heading">Image Provider</h2>



<p class="wp-block-paragraph">Before we dive deeper into the topic, I want to note that I am using PySide6, and the image provider lives under PySide6.QtQuick.</p>



<p class="wp-block-paragraph">See this decent, thorough <a href="https://doc.qt.io/qtforpython-6/PySide6/QtQuick/QQuickImageProvider.html" type="link" id="https://doc.qt.io/qtforpython-6/PySide6/QtQuick/QQuickImageProvider.html" target="_blank" rel="noreferrer noopener">documentation page on the QQuickImageProvider</a> that you may wish to examine to gain a better understanding of the concept. </p>



<p class="wp-block-paragraph">The primary purpose of the image provider is to allow the application to render images from sources other than the standard files. Good examples of such sources are the in-memory data and dynamically generated images.</p>



<p class="wp-block-paragraph">If you simply need to render a pre-existing image in a common format, then I highly recommend looking into the native QML Image component capabilities.</p>



<h2 id="h-setup" class="wp-block-heading">Setup</h2>



<p class="wp-block-paragraph"><strong>Disclosure:</strong> code casing might be inconsistent with what you are used to in Python, but I tried incorporating both QML and Python standards where applicable.</p>



<ul class="wp-block-list">
<li><strong>camelCase</strong> – function names (QML/C++ – inherited function override&nbsp;+ consistency)</li>



<li><strong>PascalCase</strong> – objects (QML/C++ – inherited base class + consistency)</li>



<li><strong>snake_case</strong> – variables (Python – standard)</li>
</ul>



<p class="wp-block-paragraph">To begin custom image provider implementation, you have to instantiate your image provider class that inherits <strong>PySide6.QtQuick.QQuickImageProvider.</strong></p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/1-custom-image-provider-definition.png" alt="Custom Image Provider Definition"/></figure>



<p class="wp-block-paragraph"><p style="text-align: center;"><em>Image 1. custom image provider definition</em></p></p>


<pre class="”brush:python”">
class CustomImageProvider(QQuickImageProvider):
    def __init__(self, image_provider_id: str):
        super().__init__(QQuickImageProvider.ImageType.Image)
        &quot;&quot;&quot;Image provider metadata.&quot;&quot;&quot;
        self.provider_id = image_provider_id

        &quot;&quot;&quot;Image provider data.&quot;&quot;&quot;
        self._images: dict[str, np.ndarray] = dict()

        &quot;&quot;&quot;Suggested utility objects.&quot;&quot;&quot;
        # self.SharedConstants = SharedConstants()
        # self._imageConstructor = ImageConstructor()
        # self._idConstructor = IdConstructor()
</pre>


<p class="wp-block-paragraph">Notice that I created a public property <strong>provider_id.</strong> You do not technically need it, but I highly recommend introducing one, especially if you are anticipating multiple image provider instances. For example, I worked on an app that required multiple tabs to be open in parallel, each with access to an image provider. Since each tab needed its own library of custom images, with image IDs not necessarily <em>globally </em>unique, I had to instantiate a unique image provider per tab to avoid data conflicts. The <strong>provider_id</strong> really helps identify which image provider to use and, more importantly, which image provider can be cleared out for garbage collection purposes as the tab closes.</p>



<p class="wp-block-paragraph">You also need to create a data structure to hold your images. A dictionary has the convenience of id-data mapping. QML will always request an image using a string id and mapping hashable string ids to image data sounds like a perfect opportunity to use a dictionary. To avoid any unexpected behavior, I recommend instantiating the data structure as an internal property and, thus, I called it simply <strong>_images.</strong></p>



<p class="wp-block-paragraph">In the comments I am also suggesting the usage of the following objects:</p>



<ul class="wp-block-list">
<li><strong>SharedConstants</strong> – implement to store and use constants that are shared across the application. Remember, if anything is used in both QML and Python and is ultimately hardcoded, then you should instantiate it as a shared constant, and that constant could be used by both QML and Python. Otherwise, any change to a hardcoded value will become a living nightmare of chasing down all the instances of that value in the code. <strong>Remember, you cannot easily, if at all, debug QML.</strong></li>



<li><strong>ImageConstructor</strong> – use this class to define functions that could be used to construct pixel data that would be stored in the <strong>_images</strong> data structure.</li>



<li><strong>IdConstructor</strong> – use this class to define functions that could be used to construct ids that would be used to store data in the <strong>_images</strong> data structure.</li>
</ul>



<h2 id="h-method-override" class="wp-block-heading">Method Override</h2>



<p class="wp-block-paragraph"><strong>QQuickImageProvider </strong>has <strong>requestPixmap</strong>, <strong>requestImage</strong> and <strong>requestTexture</strong> that you can override&nbsp;to implement your custom functionality. Each method’s signature is similar to the others, so I will focus on the <strong>requestImage</strong> method as I have worked with it the most.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/2-requestimage-override.png" alt="Requestimage Override"/></figure>



<p class="wp-block-paragraph"><p style="text-align: center;"><em>Image 2. requestImage override</em></p></p>


<pre class="”brush:python”">
    def requestImage(self, image_id: str, size: QSize, requested_size: QSize) -&gt; QImage:
        if (image_id in self._images.keys()) and (self._images[image_id] is not None):
            &quot;&quot;&quot;Retrieve the image data from the image library.&quot;&quot;&quot;
            _pixels = self._images[image_id]

            &quot;&quot;&quot;According to the documentation: 
            In all cases, size must be set to the original size of the image. 
            This is used to set the width and height of the relevant Image if 
            these values have not been set explicitly.&quot;&quot;&quot;
            image_size = QSize(_pixels.shape[1], _pixels.shape[0])
            if size:
                size = image_size

            &quot;&quot;&quot;Construct the size of the returned image.&quot;&quot;&quot;
            width = (
                requested_size.width()
                if requested_size.width() &gt; 0
                else image_size.width()
            )
            height = (
                requested_size.height()
                if requested_size.height() &gt; 0
                else image_size.height()
            )

            &quot;&quot;&quot;Construct the image.&quot;&quot;&quot;
            img = QImage(
                _pixels.data,
                height,
                width,
                QImage.Format_RGBA8888,
            )

            return img
        else:
            raise ValueError(
                self.provider_id
                + &quot; image provider was unable to find image &quot;
                + image_id
            )
</pre>


<p class="wp-block-paragraph">Each of the three methods requires a signature that includes <strong>image_id</strong>, <strong>size</strong> and <strong>requested_size</strong>. It is okay to rename those input variables, but the typing must remain the same. Nevertheless, I do not recommend changing the names.</p>



<ul class="wp-block-list">
<li><strong>image_id</strong> – the string ID of the image by which you will be looking up the pixel data in the defined <strong>_images</strong> data structure.</li>



<li><strong>size</strong> – is not technically used for anything in the Python implementation of the image provider. According to the official documentation: “<em>In all cases, size must be set to the original size of the image. This is used to set the width and height of the relevant Image if these values have not been set explicitly.</em>” This is a remnant of the C++ framework. This variable is passed into this method by reference and must be updated. Every other input is passed in by value.</li>



<li><strong>requested_size</strong> – the size of the <strong>Image</strong> component in QML that requested the image from the custom image provider.</li>
</ul>



<p class="wp-block-paragraph">The return value of the overridden&nbsp;method must be a properly constructed <strong>QImage</strong> that QML will be able to display in the application. Notice that the first input for the <strong>QImage</strong> constructor is a <strong>buffer object pointing to the start of the array’s data</strong>. This is also a C++ memory management quirk that Python has to deal with. The format also plays a big role in image rendering. The current <strong>QImage.Format_RGBA8888</strong> decodes the given data array as though there are four <strong>8-bit unsigned integers for red, green, blue, and alpha channels per pixel</strong>. This is crucial, since, if you provide the wrong array type, the displayed image will either be incorrect or won’t show up at all. QML will not throw an error, so you might spend a lot of time trying to figure out why your image is not rendering. A friend of mine told me this, I am certainly not speaking from experience…</p>



<p class="wp-block-paragraph">The sizing of the image is another topic for discussion. Depending on your implementation, you might want to keep the original size of the image in any rendering case, or, on the contrary, you might always want to resize the image to the window size. Sometimes, you might need to implement the sizing so that it is dynamic and dependent on the window state/size. Basically, what I am saying is that the sizing implementation in the code above is subject to change depending on your application needs; however, you must assign the current image original size to the passed by reference <strong>size</strong> variable.</p>



<h2 id="h-data-management" class="wp-block-heading">Data Management</h2>



<p class="wp-block-paragraph">Now that we’ve implemented the basic image provider functionality, we have to develop data management capabilities. Image data must be somehow stored in the image provider, and, since the data structure <strong>_images</strong> was defined internally, we have to define functions that will allow insertion of the new data into the dictionary as well as its removal.</p>



<p class="wp-block-paragraph">It is also important to implement data validation code that could be broken down into helper functions. This is where you make sure that the data provided for addition could be displayed using the defined <strong>QImage </strong>format.</p>



<p class="wp-block-paragraph">You can also include some of your data manipulation and ID construction code. Basically, this is the perfect opportunity to get the best use out of your predefined <strong>ImageConstructor </strong>and <strong>IdConstructor </strong>objects. You still have to make sure that the data on the output is suitable for the defined <strong>QImage </strong>format.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/3-main-image-provider-management-function.png" alt="Main Image Provider Management Function"/></figure>



<p class="wp-block-paragraph"><p style="text-align: center;"><em>Image 3. main image provider management function</em></p></p>



<p class="wp-block-paragraph">The following implementation is an example of how you can develop the data removal functionality.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/4-supplemental-management-function.png" alt="Supplemental Management Function"/></figure>



<p class="wp-block-paragraph"><p style="text-align: center;"><em>Image 4. supplemental management function</em></p></p>


<pre class="”brush:python”">

    def addOrUpdateLayer(self, layer_id: str, pixel_data: np.ndarray) -&gt; dict:
        &quot;&quot;&quot;Data validation and manipulations to prep for the render-ready format&quot;&quot;&quot;
        # Insert your data validation code
        # Insert your data manipulation code

        &quot;&quot;&quot;Map the new data to the desired id and save to the library.&quot;&quot;&quot;
        layer = {layer_id: pixel_data}
        self._images.update(layer)

        return layer

    def removeLayer(self, layer_id: str) -&gt; None:
        &quot;&quot;&quot;Apply key-value pair deletion logic&quot;&quot;&quot;
        del self._images[layer_id]
</pre>


<h2 id="h-helper-functionality" class="wp-block-heading">Helper Functionality</h2>



<p class="wp-block-paragraph">I highly recommend keeping your custom image provider as lightweight as possible for scaling and maintainability purposes; however, you may still want to implement some basic helper functions like:</p>



<ul class="wp-block-list">
<li><strong>isIDTaken</strong> – to check whether a given ID already exists in the image provider to avoid overriding&nbsp;stored data<strong>.</strong></li>



<li><strong>isImageLoaded</strong> – to check whether the data is present in the data structure before querying it.</li>



<li><strong>clearImageProviderInstance</strong> – to manage the memory that the image provider occupies.</li>
</ul>



<p class="wp-block-paragraph">Example implementation for each is presented below:</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/5-supplemental-image-provider-functionality.png" alt="Supplemental Image Provider Functionality"/></figure>



<p class="wp-block-paragraph"><p style="text-align: center;"><em>Image 5. supplemental image provider functionality</em></p></p>


<pre class="”brush:python”">
    def isIDTaken(self, image_id: str) -&gt; bool:
        return image_id in self._images.keys()

    def isImageLoaded(self, image_id: str) -&gt; bool:
        return self._images[image_id] is not None

    def clearImageProviderInstance(self):
        self._qml_engine.removeImageProvider(self._id)
</pre>


<h2 id="h-in-action" class="wp-block-heading">In Action</h2>



<p class="wp-block-paragraph">The following code snippets do not require much explanation but are a good starting point in learning how to use the custom image provider in the scope of any application. Note, we must add an image provider to the application engine.</p>



<p class="wp-block-paragraph">Since we defined the image provider class with a unique ID property, you must provide one to each image provider you insert into the application. Keep in mind that QML engine requires you to provide a unique ID in the first place, so you should just store that ID in the image provider itself.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/6-image-provider-usage-in-an-example.png" alt="Image Provider Usage in an Example"/></figure>



<p class="wp-block-paragraph"><p style="text-align: center;"><em>Image 6. image provider usage in an example</em></p></p>


<pre class="”brush:python”">
if __name__ == &quot;__main__&quot;:
    &quot;&quot;&quot;Set up the application.&quot;&quot;&quot;
    app = QApplication([])
    engine = QQmlApplicationEngine()

    &quot;&quot;&quot;Instantiate an image provider.&quot;&quot;&quot;
    unique_id = &quot;unique_image_provider_id&quot;
    image_provider = CustomImageProvider(unique_id)
    engine.addImageProvider(unique_id, image_provider)

    &quot;&quot;&quot;Add an image to the image provider.&quot;&quot;&quot;
    image_provider.addOrUpdateLayer(
        &quot;unique_image_id&quot;,
        np.array(
            [
                [
                    [255, 0, 0, 255],
                    [255, 0, 0, 255],
                    [255, 0, 0, 255],
                ],
                [
                    [0, 255, 0, 255],
                    [0, 255, 0, 255],
                    [0, 255, 0, 255],
                ],
                [
                    [0, 0, 255, 255],
                    [0, 0, 255, 255],
                    [0, 0, 255, 255],
                ],
            ],
            dtype=np.uint8,
        ),
    )

    &quot;&quot;&quot;Load and tun the app.&quot;&quot;&quot;
    engine.load(&quot;main.qml&quot;)
    app.exec()
</pre>


<p class="wp-block-paragraph">According to the code above, the example image we are defining has a 3-pixel height and a 3-pixel width. It’s a square of three colored stripes: red, green, blue with full opacity (4<sup>th</sup> alpha channel).</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/7-example-qml-code.png" alt="Example QML Code"/></figure>



<p class="wp-block-paragraph"><p style="text-align: center;"><em>Image 7. example QML code</em></p></p>


<pre class="”brush:html”">
import QtQuick 2.15
import QtQuick.Controls 2.15

ApplicationWindow {
    visible: true
    width: 600
    height: 600
    title: &quot;Custom Image App&quot;

    Image {
        anchors.fill: parent
        // Set the source to the custom image provider.
        // Include the image id if you would like to show a particular image.
        source: &quot;image://unique_image_provider_id/unique_image_id&quot;
    }
}
</pre>


<p class="wp-block-paragraph">I am choosing to keep the QML code fairly simple and straightforward. This code snippet does not necessarily follow any coding standards, but rather serves as a quick and dirty playground to show off some custom image provider capabilities.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/8-produced-result.png" alt="Produced Result"/></figure>



<p class="wp-block-paragraph"><p style="text-align: center;"><em>Image 8. produced result</em></p></p>



<p class="wp-block-paragraph">The produced result is just as we expected, a stretched out 3&#215;3 pixel image! Notice that the <strong>Image </strong>component anchors onto its parent, so the <strong>requestedSize</strong> will be inherited from the <strong>ApplicationWindow</strong> component size.</p>



<p class="wp-block-paragraph">We could also set the <strong>requestedSize</strong> manually in QML. This way, the size of the constructed image will not change dynamically with the <strong>ApplicationWindow</strong>.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/9-example-of-setting-the-image-size-manually.png" alt="Example of Setting the Image Size Manually"/></figure>



<p class="wp-block-paragraph"><p style="text-align: center;"><em>Image 9. example of setting the image size manually</em></p></p>


<pre class="”brush:html”">
import QtQuick 2.15
import QtQuick.Controls 2.15

ApplicationWindow {
    visible: true
    width: 600
    height: 600
    title: &quot;Custom Image App&quot;

    Image {
        width: 450
        height: 300
        // Set the source to the custom image provider.
        // Include the image id if you would like to show a particular image.
        source: &quot;image://unique_image_provider_id/unique_image_id&quot;
    }
}
</pre>


<p class="wp-block-paragraph">Notice the difference in the newly rendered result:</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/10-result-of-setting-the-image-size-manually.png" alt="Result of Setting the Image Size Manually"/></figure>



<p class="wp-block-paragraph"><p style="text-align: center;"><em>Image 10. result of setting the image size manually</em></p></p>



<h2 id="h-alternative-setup" class="wp-block-heading">Alternative Setup</h2>



<p class="wp-block-paragraph">A less recommended, but valid nonetheless, implementation is to let the custom image provider insert itself into the application upon instantiation.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/11-alternative-custom-image-provider-definition.png" alt="Alternative Custom Image Provider Definition"/></figure>



<p class="wp-block-paragraph"><p style="text-align: center;"><em>Image 11. alternative custom image provider definition</em></p></p>


<pre class="”brush:python”">
class CustomImageProvider(QQuickImageProvider):
    def __init__(
        self, image_provider_id: str, qml_application_engine: QQmlApplicationEngine
    ):
        super().__init__(QQuickImageProvider.ImageType.Image)
        &quot;&quot;&quot;Image provider metadata.&quot;&quot;&quot;
        self.provider_id = image_provider_id

        &quot;&quot;&quot;Handle image provider self insertion into the application.&quot;&quot;&quot;
        self._qml_application_engine = qml_application_engine
        self._qml_application_engine.addImageProvider(self.provider_id, self)

        &quot;&quot;&quot;Image provider data.&quot;&quot;&quot;
        self._images: dict[str, np.ndarray] = dict()

        &quot;&quot;&quot;Suggested utility objects.&quot;&quot;&quot;
        # self.SharedConstants = SharedConstants()
        # self._imageConstructor = ImageConstructor()
        # self._idConstructor = IdConstructor()
</pre>


<p class="wp-block-paragraph">The following is an example of such an image provider in action.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/12-example-usage-of-the-alternative-cuatom-image-provider.png" alt="Example Usage of the Alternative Custom Image Provider"/></figure>



<p class="wp-block-paragraph"><p style="text-align: center;"><em>Image 12. example usage of the alternative custom image provider</em></p></p>


<pre class="”brush:python”">
if __name__ == &quot;__main__&quot;:
    &quot;&quot;&quot;Set up the application.&quot;&quot;&quot;
    app = QApplication([])
    engine = QQmlApplicationEngine()

    &quot;&quot;&quot;Instantiate an image provider.&quot;&quot;&quot;
    unique_id = &quot;unique_image_provider_id&quot;
    image_provider = CustomImageProvider(unique_id, engine)

    &quot;&quot;&quot;Add an image to the image provider.&quot;&quot;&quot;
    image_provider.addOrUpdateLayer(
        &quot;unique_image_id&quot;,
        np.array(
            [
                [
                    [255, 0, 0, 255],
                    [255, 0, 0, 255],
                    [255, 0, 0, 255],
                ],
                [
                    [0, 255, 0, 255],
                    [0, 255, 0, 255],
                    [0, 255, 0, 255],
                ],
                [
                    [0, 0, 255, 255],
                    [0, 0, 255, 255],
                    [0, 0, 255, 255],
                ],
            ],
            dtype=np.uint8,
        ),
    )

    &quot;&quot;&quot;Load and tun the app.&quot;&quot;&quot;
    engine.load(&quot;main.qml&quot;)
    app.exec()
</pre>


<h2 id="h-notes-and-tips" class="wp-block-heading">Notes and Tips</h2>



<ol class="wp-block-list">
<li>Keep your image provider lightweight. Put all the functionality you think is relevant to it somewhere else, because chances are, it is not. The image provider should really be treated as a data structure that has functionality only to store and remove images.</li>



<li>Make your image provider usable in every place of your application. Avoid putting select-component/window-only functionality in here.</li>



<li>This implementation will also likely work in PySide2 since that is where I originally developed it.</li>
</ol>



<p class="wp-block-paragraph">&nbsp;<b data-stringify-type="bold">Learn more about&nbsp;</b><b data-stringify-type="bold"><a data-sk="tooltip_parent" data-stringify-link="https://static.dmcinfo.com/latest-thinking/blog/id/10393/resizing-uis-with-qml-layouts" delay="150" href="https://static.dmcinfo.com/latest-thinking/blog/id/10393/resizing-uis-with-qml-layouts" rel="noopener noreferrer" target="_blank">Resizing UIs with QML Layouts</a></b><b data-stringify-type="bold">&nbsp;and&nbsp;</b><b data-stringify-type="bold"><a data-sk="tooltip_parent" data-stringify-link="https://static.dmcinfo.com/contact" delay="150" href="https://static.dmcinfo.com/contact" rel="noopener noreferrer" target="_blank">contact us</a></b><b data-stringify-type="bold">&nbsp;today for your next project.</b></p>
<p>The post <a href="https://static.dmcinfo.com/blog/17084/custom-image-provider-implementation-in-pyside/">Custom Image Provider Implementation in PySide</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>3 Common Pitfalls of Theme Customization with Material UI </title>
		<link>https://static.dmcinfo.com/blog/17372/3-common-pitfalls-of-theme-customization-with-material-ui/</link>
		
		<dc:creator><![CDATA[Sam Wallace]]></dc:creator>
		<pubDate>Wed, 19 Jul 2023 13:14:15 +0000</pubDate>
				<category><![CDATA[Application Development]]></category>
		<category><![CDATA[User Interface Design]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/17372/3-common-pitfalls-of-theme-customization-with-material-ui/</guid>

					<description><![CDATA[<p>Material UI is a great tool for speeding up the development process of your React app. The library offers out-of-the-box React UI components with built-in properties that greatly simplify implementing the styling and interaction requirements of your product. Out-of-the-box UI rarely matches an application&#8217;s predetermined design alone, however. In these situations, we are required to [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/17372/3-common-pitfalls-of-theme-customization-with-material-ui/">3 Common Pitfalls of Theme Customization with Material UI </a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Material UI is a great tool for speeding up the development process of your React app. The library offers out-of-the-box React UI components with built-in properties that greatly simplify implementing the styling and interaction requirements of your product. </p>



<p class="wp-block-paragraph">Out-of-the-box UI rarely matches an application&#8217;s predetermined design alone, however. In these situations, we are required to open these components and tinker with their CSS styles directly.</p>



<p class="wp-block-paragraph">Material UI offers extensive documentation for component styling and customization, but the actual process of reworking these styles can be confusing and frustrating. In this blog post, I hope to simplify this process by covering 3 common pitfalls when overriding Material UI styles.&nbsp;</p>



<p class="wp-block-paragraph">This post will exemplify these pitfalls by overriding styles on an MUI TextField component. The implementation of these examples can be found in this <a href="https://codesandbox.io/p/sandbox/brave-gauss-qb2mbs" data-type="link" data-id="https://codesandbox.io/p/sandbox/brave-gauss-qb2mbs" target="_blank" rel="noreferrer noopener">Code Sandbox</a>. The source code we will start off with is a single TextField component rendered to the page, with style overrides controlled with MUI’s built-in createTheme() function: </p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">JavaScript</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>const theme = createTheme({
 components: {
   MuiInputBase: {
     styleOverrides: {
       root: {}
     }
   }
 }
});
export default function App() {
 return (
   
     
       
         }}
       />
     
   
 );
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4FC1FF">theme</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">createTheme</span><span style="color: #D4D4D4">({</span></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">components:</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">   </span><span style="color: #9CDCFE">MuiInputBase:</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">     </span><span style="color: #9CDCFE">styleOverrides:</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">       </span><span style="color: #9CDCFE">root:</span><span style="color: #D4D4D4"> {}</span></span>
<span class="line"><span style="color: #D4D4D4">     }</span></span>
<span class="line"><span style="color: #D4D4D4">   }</span></span>
<span class="line"><span style="color: #D4D4D4"> }</span></span>
<span class="line"><span style="color: #D4D4D4">});</span></span>
<span class="line"><span style="color: #C586C0">export</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">default</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">App</span><span style="color: #D4D4D4">() {</span></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> (</span></span>
<span class="line"><span style="color: #D4D4D4">   </span></span>
<span class="line"><span style="color: #D4D4D4">     </span></span>
<span class="line"><span style="color: #D4D4D4">       </span></span>
<span class="line"><span style="color: #D4D4D4">         }}</span></span>
<span class="line"><span style="color: #D4D4D4">       /&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">     </span></span>
<span class="line"><span style="color: #D4D4D4">   </span></span>
<span class="line"><span style="color: #D4D4D4"> );</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">With no overrides in place to begin, the rendered page looks like this:&nbsp;</p>



<p class="wp-block-paragraph">There are multiple approaches to&nbsp;specifying style overrides within your project, and you may require something different than what is provided in this&nbsp;demo. For more information on the different approaches for locating style overrides, check out the&nbsp;<a href="https://mui.com/material-ui/customization/how-to-customize/" rel="noreferrer noopener" target="_blank">MUI documentation.</a>&nbsp;&nbsp;</p>



<h2 id="h-part-1-materialui-slot-selectors-nbsp" class="wp-block-heading">Part 1: MaterialUI Slot Selectors&nbsp;</h2>



<p class="wp-block-paragraph">Style overrides are most commonly located in a “theme” object. This object designates custom styles to components&nbsp;and the “slots” that compose a given component. Each slot maps to a single HTML element rendered within the larger component.&nbsp;</p>



<p class="wp-block-paragraph">To add or override a style, we specify both the component and slot that we are targeting. The styles we specify are applied in a CSS class specific to that element. In the example below, we target the input element within an MUI TextField, which is accessed by the MUI component MuiInputBase and slot root:&nbsp;&nbsp;</p>


<pre class="”brush:pascal”">
const theme = createTheme({
  components: {
    MuiInputBase: {
      styleOverrides: {
        root: {
          color: &quot;green&quot;
        }
      }
    }
  }
});
</pre>


<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Material-UI-Screenshot-1.png" alt="Screenshot of code on a computer"/></figure>



<p class="wp-block-paragraph"><strong>Pitfall: Choosing the Wrong Slot&nbsp;</strong></p>



<p class="wp-block-paragraph">When we specify styles for a component, they may appear in the rendered CSS but not induce a visible change on the page. In this case, the slot you specified may not be the correct one to target. A good practice to prevent this issue is to determine where the styles you want to override are initially applied and ensure you specify those slots in your theme.&nbsp;</p>



<p class="wp-block-paragraph">For example,&nbsp;say that I am trying to both increase the width of the TextField border and remove the preset borderRadius. If I apply both updates to the MuiInputBase-root slot, I&nbsp;get the following result:&nbsp;</p>


<pre class="”brush:pascal”">
const theme = createTheme({
  components: {
    MuiOutlinedInput: {
      styleOverrides: {
        root: {
          borderWidth: 3,
          borderRadius: 0
        }
      }
    }
  }
});

</pre>


<figure class="wp-block-image size-full"><img decoding="async" width="267" height="81" src="https://static.dmcinfo.com/wp-content/uploads/2023/07/screenshot-of-rendered-page-2.png" alt="" class="wp-image-36156"/></figure>



<p class="wp-block-paragraph">As you can see, the border has been removed, but the box width remains the same. If I investigate the styling specified for each slot, I see that there is a default value of borderRadius specified for MuiOutlinedInput-root, but the default borderWidth set on MuiOutlinedInput-notchedOutline is still being applied:</p>



<p class="wp-block-paragraph">If I move this override to the correct slot, we can see the desired output:&nbsp;</p>


<pre class="”brush:pascal”">
const theme = createTheme({
  components: {
    MuiOutlinedInput: {
      styleOverrides: {
        root: {
          borderRadius: 0
        },
        notchedOutline:{
          borderWidth: 3
        }
      }
    }
  }
});
</pre>


<figure class="wp-block-image size-full"><img decoding="async" width="271" height="82" src="https://static.dmcinfo.com/wp-content/uploads/2023/07/screenshot-of-rendered-page-3.png" alt="" class="wp-image-36157"/></figure>



<h2 id="h-part-2-correct-mui-class-reference-syntax-nbsp" class="wp-block-heading">Part 2: Correct MUI Class Reference Syntax&nbsp;</h2>



<p class="wp-block-paragraph">Beyond the theme specification exemplified above, MUI theme overrides allow string keys that specify selectors, providing greater control over the styles applied.&nbsp;&nbsp;</p>



<p class="wp-block-paragraph">There are many features of this string notation, but two features are used most frequently:&nbsp;</p>



<ul class="wp-block-list">
<li>Specifying the component-slot names of a descendant MUI component (akin to CSS descendant combinators)&nbsp;</li>



<li>Specifying a state selector that applies styles to the component only if it is in a certain state (akin to CSS pseudo-classes)&nbsp;</li>
</ul>



<p class="wp-block-paragraph">An example of both can be seen below:&nbsp;</p>


<pre class="”brush:pascal”">const theme = createTheme({
 components: {
   MuiOutlinedInput: {
     styleOverrides: {
       root: {
         borderRadius: 0,
         "&amp;. MuiSvgIcon-root": {
           color: "rgb(100,100,100)"
         },
         "&amp;.Mui-focused": {
           backgroundColor: "rgb(220,240,250)",
         }
       },
       notchedOutline: {
         borderWidth: 3,
         borderColor: "black"
       }
     }
   }
 }
})
</pre>


<figure class="wp-block-image size-full"><img decoding="async" width="260" height="74" src="https://static.dmcinfo.com/wp-content/uploads/2023/07/screenshot-of-rendered-page-4.png" alt="" class="wp-image-36158"/></figure>



<p class="wp-block-paragraph">Here, we have added an adornment icon to the TextField, which has a default color of black (“rgb(0,0,0)”), but we can specify a selector for this MUI component and update its color to a dark gray (“rgb(220,240,250)”). Additionally, we can set the background color of the field whenever the field is in focus by specifying a background color in the state selector “.Mui-focused”.</p>



<h3 id="h-pitfall-string-selector-syntax" class="wp-block-heading">Pitfall: String Selector Syntax</h3>



<p class="wp-block-paragraph">These string-notation selectors are fantastic for adding a higher level of specificity to your overrides, but they also fall outside of the typing for MUI themes – every key with this notation is just a string. This means that applying styles to incorrectly formatted selectors will fail silently. Given the extensive feature set of these string selectors, consulting the MUI documentation on formatting is best for more complex cases. For simpler and more common cases like the one above, here is a quick tip that may save you some time:</p>



<ul class="wp-block-list">
<li>Descendant selectors follow the notation &#8220;&amp; .[Component]-[Slot]&#8221;. Note the space after the ampersand.&nbsp;&nbsp;</li>



<li>State selectors follow the notation &#8220;&amp;.[state]&#8221; with no space after the ampersand.&nbsp;</li>
</ul>



<p class="wp-block-paragraph">This small difference is due to how these strings are parsed into plain CSS selectors. Descendant components are implemented with descendant CSS combinators as mentioned above, which require&nbsp;a space. State selectors are simply appended to the existing component class name, so the space is not included. Failing to follow this format for either type of selector results in styles not being applied. Below, we can see that neither the background highlight nor the color modification of the adornment icon is applied when the format is incorrect.&nbsp;</p>


<pre class="”brush:pascal”">const theme = createTheme({
 components: {
   MuiOutlinedInput: {
     styleOverrides: {
       root: {
         borderRadius: 0,
         "&amp;. MuiSvgIcon-root": {
           color: "rgb(100,100,100)"
         },
         "&amp;.Mui-focused": {
           backgroundColor: "rgb(220,240,250)",
         }
       },
       notchedOutline: {
         borderWidth: 3,
         borderColor: "black"
       }
     }
   }
 }
});
</pre>


<figure class="wp-block-image size-full"><img decoding="async" width="286" height="81" src="https://static.dmcinfo.com/wp-content/uploads/2023/07/screenshot-of-rendered-page-5.png" alt="" class="wp-image-36159"/></figure>



<h2 id="h-part-3-selector-specificity-is-correct-nbsp" class="wp-block-heading">Part 3: Selector Specificity is Correct&nbsp;</h2>



<p class="wp-block-paragraph">The nested selector structure shown in the last two examples follows the same rule as applying classes to HTML elements: if two classes are applied to an element and one class has a more specific selector than the other, then the more specific class’s styles will be displayed with higher priority than the other.</p>



<p class="wp-block-paragraph">In MUI theme overrides, specificity is determined by matching slot selectors and state selectors, as well as any base CSS selector.&nbsp;</p>



<h3 id="h-pitfall-override-s-selector-is-still-not-a-higher-specificity-than-the-out-of-the-box-styling" class="wp-block-heading">Pitfall: Override&#8217;s selector is still not a higher specificity than the out-of-the-box styling</h3>



<p class="wp-block-paragraph">There are already many selectors in the default styles of an MUI component that are very specific to certain elements within it. If your style override does not appear and the default style is still applied, check the style&#8217;s specificity and try to match it to your overriding selector.&nbsp;</p>



<p class="wp-block-paragraph">I’ll demonstrate this by&nbsp;extending&nbsp;the example from the last two sections. If you look at the image from the last section, you&#8217;ll notice that our custom black border is not present when the text box is selected. The border becomes thinner, and the color changes to a darker blue.</p>



<p class="wp-block-paragraph">If we dig around the DOM a bit when the TextField component is in focus, we can see a default TextField style that is making this change with the help of the higher specificity of the “.Mui-focused” state selector:&nbsp;</p>



<p class="wp-block-paragraph">If we want to override the border color of the text field when it is in focus, we need to match the level of specificity from the selector of the default style:&nbsp;</p>


<pre class="”brush:pascal”">const theme = createTheme({
 components: {
   MuiOutlinedInput: {
     styleOverrides: {
       root: {
         borderRadius: 0,
         "&amp;. MuiSvgIcon-root": {
           color: "rgb(100,100,100)"
         },
         "&amp;.Mui-focused": {
           backgroundColor: "rgb(220,240,250)",
           "&amp; .MuiOutlinedInput-notchedOutline":{
             borderColor: "black"
           }
         }
       },
       notchedOutline: {
         borderWidth: 3,
         borderColor: "black"
       }
     }
   }
 }
});
</pre>


<p class="wp-block-paragraph">Now, if we look at the DOM and the resultant page, we see that the more specific default style has been successfully overridden:&nbsp;</p>



<p class="wp-block-paragraph">Another important consideration here is that the selectors must be nested in the right order to be successfully applied;&nbsp;if the .MUI-focused state selector is nested in MuiOutlinedInput-notchedOutline class selector, then the style would not apply.&nbsp;</p>



<h2 id="h-conclusion" class="wp-block-heading">Conclusion</h2>



<p class="wp-block-paragraph">MUI’s default styles and style overrides provide a very high level of configurability to web developers, but opening their out-of-the-box solutions can be tricky. The pitfalls exemplified are not the only possible issues, but from my experience, keeping these common problems in mind will considerably reduce the time needed to debug your styles.&nbsp;</p>



<p class="wp-block-paragraph"><strong>Learn more about DMC’s&nbsp;<a href="https://static.dmcinfo.com/services/application-development/web-application-development">Web Application Development</a>&nbsp;services and&nbsp;<a href="https://static.dmcinfo.com/contact">contact us</a>&nbsp;for your next project.&nbsp;</strong></p>



<p class="wp-block-paragraph"></p>
<p>The post <a href="https://static.dmcinfo.com/blog/17372/3-common-pitfalls-of-theme-customization-with-material-ui/">3 Common Pitfalls of Theme Customization with Material UI </a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>LVGL for International GUI Design</title>
		<link>https://static.dmcinfo.com/blog/17764/lvgl-for-international-gui-design/</link>
		
		<dc:creator><![CDATA[Ben Dyer]]></dc:creator>
		<pubDate>Wed, 01 Mar 2023 10:12:27 +0000</pubDate>
				<category><![CDATA[Embedded Development & Programming]]></category>
		<category><![CDATA[User Interface Design]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[embedded]]></category>
		<category><![CDATA[i18n]]></category>
		<category><![CDATA[internationalization]]></category>
		<category><![CDATA[LVGL]]></category>
		<category><![CDATA[microcontroller]]></category>
		<category><![CDATA[multi-language]]></category>
		<category><![CDATA[user interface]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/17764/lvgl-for-international-gui-design/</guid>

					<description><![CDATA[<p>Creating a high-quality user interface that can run on embedded systems is a challenging task, and that’s doubly (or perhaps triply) true if it’s intended for an international user base. As with any difficult job, however, it becomes much more manageable with the right tools. Read on to learn the basics of one such tool, [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/17764/lvgl-for-international-gui-design/">LVGL for International GUI Design</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><!-- Injected  Highlight.js Code --><script type="text/javascript" src="/Providers/HtmlEditorProviders/CKEditor/plugins/codesnippet/lib/highlight/highlight.pack.js?ver=1790905719"></script><link type="text/css" rel="stylesheet" href="/Providers/HtmlEditorProviders/CKEditor/plugins/codesnippet/lib/highlight/styles/default.css?ver=1790905719"/><script type="text/javascript">window.onload = function() {var aCodes = document.getElementsByTagName('pre');for (var i=0; i < aCodes.length;i++){hljs.highlightBlock(aCodes[i]);} };</script></p>


<p class="wp-block-paragraph">Creating a high-quality user interface that can run on embedded systems is a challenging task, and that’s doubly (or perhaps triply) true if it’s intended for an international user base.</p>



<p class="wp-block-paragraph">As with any difficult job, however, it becomes much more manageable with the right tools. Read on to learn the basics of one such tool, LVGL, and its associated utilities.</p>



<h2 id="h-getting-started-with-lvgl" class="wp-block-heading">Getting Started with LVGL</h2>



<p class="wp-block-paragraph">In order to develop with LVGL, it will need&nbsp;to be ported to your platform of choice.</p>



<p class="wp-block-paragraph">First, pull the latest release of LVGL into a project configured for your target and create “lv_conf.h” from the included template. This file contains a variety of parameters for tweaking the library’s behavior, but they can be left at their default values for now. Add a call to <strong>lv_init</strong>&nbsp;to your program, ensuring it’s in a location where it will occur before any other LVGL functions are called.</p>



<p class="wp-block-paragraph">Next, you will need to define drivers for the display showing your UI and any input devices used to interact with it. The specifics of these drivers will vary greatly from project to project, and LVGL already has excellent documentation on porting, so only the general structure will be covered here.</p>



<p class="wp-block-paragraph">In simple cases, you will only need to allocate some memory to act as a draw buffer, define the resolution of the display, and implement a function to send the information LVGL places into the draw buffer to your screen.&nbsp;The example below shows a basic setup, but additional configuration options exist to implement things like double-buffering or screen rotation.</p>



<p class="wp-block-paragraph"></p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">C</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>static lv_color_t draw_buffer&#91;SCREEN_HOR_RES * SCREEN_VER_RES / 10&#93;;
static lv_disp_drv_t disp_drv;
static lv_disp_draw_buf_t disp_buf;

void flush_buffer_callback(lv_disp_drv_t* disp_drv, const lv_area_t* area, lv_color_t* color_p);

lv_disp_t* lvgl_display_port_init()
{
    //configure any platform specific peripherals here

    //set up draw buffer
    lv_disp_draw_buf_init(&amp;disp_buf, draw_buffer, NULL, SCREEN_HOR_RES * SCREEN_VER_RES / 10);

    //initialize display driver
    lv_disp_drv_init(&amp;disp_drv);

    //configure display driver
    disp_drv.draw_buf = &amp;disp_buf;
    disp_drv.hor_res = SCREEN_HOR_RES;
    disp_drv.ver_res = SCREEN_VER_RES;
    disp_drv.flush_cb = flush_buffer_callback;

    //set optional fields to customize display driver here
   
    //finalize driver setup
    return lv_disp_drv_register(&amp;disp_drv);
}

void flush_buffer_callback(lv_disp_drv_t* disp_drv, const lv_area_t* area, lv_color_t* color_p)
{
    /* copy pixels from 'color_p' to the area of the screen described by 'area' */
}</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">static</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">lv_color_t</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">draw_buffer</span><span style="color: #D4D4D4">&#91;SCREEN_HOR_RES * SCREEN_VER_RES / </span><span style="color: #B5CEA8">10</span><span style="color: #D4D4D4">&#93;;</span></span>
<span class="line"><span style="color: #569CD6">static</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">lv_disp_drv_t</span><span style="color: #D4D4D4"> disp_drv;</span></span>
<span class="line"><span style="color: #569CD6">static</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">lv_disp_draw_buf_t</span><span style="color: #D4D4D4"> disp_buf;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">void</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">flush_buffer_callback</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">lv_disp_drv_t</span><span style="color: #D4D4D4">* </span><span style="color: #9CDCFE">disp_drv</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">lv_area_t</span><span style="color: #D4D4D4">* </span><span style="color: #9CDCFE">area</span><span style="color: #D4D4D4">, </span><span style="color: #4EC9B0">lv_color_t</span><span style="color: #D4D4D4">* </span><span style="color: #9CDCFE">color_p</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #4EC9B0">lv_disp_t</span><span style="color: #D4D4D4">* </span><span style="color: #DCDCAA">lvgl_display_port_init</span><span style="color: #D4D4D4">()</span></span>
<span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">//configure any platform specific peripherals here</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">//set up draw buffer</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">lv_disp_draw_buf_init</span><span style="color: #D4D4D4">(&amp;disp_buf, draw_buffer, </span><span style="color: #569CD6">NULL</span><span style="color: #D4D4D4">, SCREEN_HOR_RES * SCREEN_VER_RES / </span><span style="color: #B5CEA8">10</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">//initialize display driver</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">lv_disp_drv_init</span><span style="color: #D4D4D4">(&amp;disp_drv);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">//configure display driver</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">disp_drv</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">draw_buf</span><span style="color: #D4D4D4"> = &amp;disp_buf;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">disp_drv</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">hor_res</span><span style="color: #D4D4D4"> = SCREEN_HOR_RES;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">disp_drv</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">ver_res</span><span style="color: #D4D4D4"> = SCREEN_VER_RES;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">disp_drv</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">flush_cb</span><span style="color: #D4D4D4"> = flush_buffer_callback;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">//set optional fields to customize display driver here</span></span>
<span class="line"><span style="color: #D4D4D4">   </span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">//finalize driver setup</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">lv_disp_drv_register</span><span style="color: #D4D4D4">(&amp;disp_drv);</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">void</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">flush_buffer_callback</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">lv_disp_drv_t</span><span style="color: #D4D4D4">* </span><span style="color: #9CDCFE">disp_drv</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">lv_area_t</span><span style="color: #D4D4D4">* </span><span style="color: #9CDCFE">area</span><span style="color: #D4D4D4">, </span><span style="color: #4EC9B0">lv_color_t</span><span style="color: #D4D4D4">* </span><span style="color: #9CDCFE">color_p</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #6A9955">    /* copy pixels from &apos;color_p&apos; to the area of the screen described by &apos;area&apos; */</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>


<pre><code class="language-cpp">
</code></pre>


<p class="wp-block-paragraph"><span id="cke_bm_275C" style="display: none;">&nbsp;</span></p>



<p class="wp-block-paragraph">Configuring an input device follows a similar process. Use <strong>lv_indev_drv_init</strong>&nbsp;to set up the driver, define its type,&nbsp;attach a function for reading its value, and register it using <strong>lv_indev_drv_register</strong>.<span id="cke_bm_399C" style="display: none;">&nbsp;</span></p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">C</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>static lv_indev_drv_t indev_drv;
void input_read(lv_indev_drv_t *indev_drv, lv_indev_data_t *data);

void lvgl_indev_port_init(void);
{
    //configure any necessary platform specific peripherals here

    //set up input device driver
    lv_indev_drv_init(&amp;indev_drv);

    //configure input device driver
    indev_drv.type = LV_INDEV_TYPE_POINTER;
    indev_drv.read_cb = input_read;
    
    //finalize driver setup
    lv_indev_t* touch_indev = lv_indev_drv_register(&amp;indev_drv);
}

void input_read(lv_indev_drv_t *indev_drv, lv_indev_data_t *data)
{
    /* Read location from input device (i.e. last touch location on a touchscreen) */

    /* Read state from input device (i.e. is a touchscreen currently being touched) */

    /* Store current location (x, y) and state (pressed, released) in 'data' */
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">static</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">lv_indev_drv_t</span><span style="color: #D4D4D4"> indev_drv;</span></span>
<span class="line"><span style="color: #569CD6">void</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">input_read</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">lv_indev_drv_t</span><span style="color: #D4D4D4"> *</span><span style="color: #9CDCFE">indev_drv</span><span style="color: #D4D4D4">, </span><span style="color: #4EC9B0">lv_indev_data_t</span><span style="color: #D4D4D4"> *</span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">void</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">lvgl_indev_port_init</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">void</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">//configure any necessary platform specific peripherals here</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">//set up input device driver</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">lv_indev_drv_init</span><span style="color: #D4D4D4">(&amp;indev_drv);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">//configure input device driver</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">indev_drv</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">type</span><span style="color: #D4D4D4"> = LV_INDEV_TYPE_POINTER;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">indev_drv</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">read_cb</span><span style="color: #D4D4D4"> = input_read;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955">//finalize driver setup</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #4EC9B0">lv_indev_t</span><span style="color: #D4D4D4">* touch_indev = </span><span style="color: #DCDCAA">lv_indev_drv_register</span><span style="color: #D4D4D4">(&amp;indev_drv);</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">void</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">input_read</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">lv_indev_drv_t</span><span style="color: #D4D4D4"> *</span><span style="color: #9CDCFE">indev_drv</span><span style="color: #D4D4D4">, </span><span style="color: #4EC9B0">lv_indev_data_t</span><span style="color: #D4D4D4"> *</span><span style="color: #9CDCFE">data</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #6A9955">    /* Read location from input device (i.e. last touch location on a touchscreen) */</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">    /* Read state from input device (i.e. is a touchscreen currently being touched) */</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">    /* Store current location (x, y) and state (pressed, released) in &apos;data&apos; */</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">&nbsp;</p>



<p class="wp-block-paragraph">With the display and input device drivers implemented, the final step is to create an environment for LVGL to run in. In simple applications, this might be an infinite loop at the end of main function, while more complex applications may utilize an RTOS (real-time operating system) and give LVGL its own thread. Many approaches will work as long as <strong>lv_tick_inc</strong>&nbsp;and <strong>lv_timer_handler</strong>&nbsp;are called periodically, with <strong>lv_tick_inc</strong>&nbsp;occurring at least as frequently as <strong>lv_timer_handler</strong>.</p>



<p class="wp-block-paragraph">Note that LVGL functions are not inherently thread-safe or interrupt-safe; if using interrupts or an RTOS, utilize synchronization tools like mutexes or take care to limit calls to LVGL such that they cannot overlap.</p>



<p class="wp-block-paragraph">With all of the above in place, LVGL should be ready to use.</p>



<h2 id="h-internationalization-tools" class="wp-block-heading">Internationalization Tools</h2>



<p class="wp-block-paragraph">In addition to the base library, LVGL has several supplementary tools to aid in development. When creating a UI for an international user base, two such tools stand out as essential:&nbsp;LVGL’s internationalization library, which provides&nbsp;simple tools for text substitution, and LVGL's&nbsp;font converter, which allows a developer to parse glyphs from several fonts into a single file for use with LVGL.</p>



<p class="wp-block-paragraph"><span style="font-family:arial;">For both of these tools, you will need node.js (at least version 14) and the&nbsp;package manager it comes bundled with (called npm). You can</span> <span style="font-family:arial;"><a href="https://nodejs.org/en/download/" type="link" id="https://nodejs.org/en/download/">download them</a>&nbsp;here. Sticking with the default installation options will work for the tools covered here.</span></p>



<p class="wp-block-paragraph"><span style="font-family:arial;">After installing, ensure that both node.js and npm are added to your system PATH. Open command prompt, and install the font converter with </span><strong>npm i lv_font_conv -g</strong><span style="font-family:arial;"> and the internationalization library with <strong>npm i lv_i18n -g</strong> Both tools should now be usable in your project.</span></p>



<h2 id="h-lv-i18n" class="wp-block-heading">lv_i18n</h2>



<p class="wp-block-paragraph"><span style="font-family:arial;">The process described below was adapted from the setup instructions provided with lv_i18n&nbsp;with notes from personal experience. For the original instructions, see the <a href="https://github.com/lvgl/lv_i18n" rel="no follow" target="_blank">lv_i18n github</a>.</span></p>



<p class="wp-block-paragraph">Start off with a simple example, and wrap any text which will be translated in <strong>_( )</strong>. For strings containing plurals, <strong>_p( )</strong>&nbsp;can be used instead to support languages with different pluralization rules from your base language. Include “lv_i18n.h” (this file doesn’t exist yet as&nbsp;it will be generated by the tool later) and, after initializing LVGL, call <code>lv_i18n_init</code>&nbsp;and <code>lv_i18n_set_locale</code>. The locale can be set to any language that you plan to support, and it can be changed any time that it’s safe to call an LVGL API function.</p>



<p class="wp-block-paragraph"><span style="font-family:arial;">Next, create a folder to store translations, add a .yml file for each language you plan to support (including the language you are developing in), and title the files&nbsp;with <a href="https://www.andiamo.co.uk/resources/iso-language-codes/" rel="no follow" target="_blank">language codes</a>. Write the language code, followed by a colon, into the first line of each file (ex: Portuguese would have a file called “pt.yml”, and it’s first line would be “pt:”). Once your example is done, from a command prompt in your project, run the following (without angle brackets):</span></p>



<p class="wp-block-paragraph"><code>lv_i18n extract -s ‘&lt;path to your source files&gt;/*.+(c|cpp|h|hpp)’ -t ‘&lt;path to your yml translations&gt;/*.yml’ </code></p>



<p class="wp-block-paragraph"><span style="font-family:arial;">This will populate the translation files with a list of every string from your project wrapped in <code>_( )</code>. Next to each, add its translation in the language corresponding to the yml file it’s in. To implement these translations, run the following:</span><br>
<br>
<code>lv_i18n compile -t ‘&lt;path to your yml translations&gt;/*.yml’ -o ‘&lt;path where you want lv_i18n.h to go&gt;’</code><br>
<br>
<span style="font-family:arial;">The output location of this command will receive lv_i18n.h and lv_i18n.c, which will contain all of your translations in a form that the tool can reference. It will need to be accessible by any file that calls <code>_( )</code>, so set up its location accordingly. </span></p>



<p class="wp-block-paragraph"><span style="font-family:arial;">Now, your example should be ready to run. Any time that code containing a string wrapped in <code>_( )</code> executes, the current locale will be checked and the string will be substituted for its translation in that locale. This is a simple, literal substitution, so anything referencing the string will be affected, not just LVGL functions. Additionally, if new text is added, you will need to run <code>lv_i18n extract</code> and <code>lv_i18n compile</code> again.</span></p>



<h2 id="h-lv-font-conv" class="wp-block-heading">lv_font_conv</h2>



<p class="wp-block-paragraph"><span style="font-family:arial;">If one of your&nbsp;languages uses&nbsp;a script other than the Latin alphabet, you may notice missing characters when its translation is&nbsp;displayed. This is where the font converter comes in. Most fonts don’t describe a glyph for every Unicode character, so you will need to either find one that has all the characters you need&nbsp;or create one by splicing together a few fonts. </span></p>



<p class="wp-block-paragraph"><span style="font-family:arial;">First, prepare a list of characters needed, or ranges of characters. Even if you have a font which contains all the characters needed, it’s likely that it also contains many that you don’t, and fonts take up a lot of space (especially physically larger ones; by default, LVGL stores them as byte arrays, and more pixels means more bytes). </span></p>



<p class="wp-block-paragraph">Next, parse this list into a font converter call. Broadly, calls to the font converter are structured as a sequential list of font files, which characters to take from them, and then a few parameters to customize the output. Supply a path to the font file with <code>--font</code>, specify which characters to include from it with <code>--range</code>&nbsp;or <code>--symbols</code>, and repeat for each font to be included.</p>



<p class="wp-block-paragraph">When adding characters, <code>--symbols</code>&nbsp;accepts a list of characters. Duplicates are ignored, so you can freely copy and paste everything from one language’s translation into this argument, but be careful to remove any spaces as they may be treated as the end of the argument. <code>--range</code>&nbsp;accepts a single Unicode value or a contiguous range of Unicode values. See <a href="https://jrgraphix.net/research/unicode.php" rel="no follow" target="_blank">Unicode ranges</a> for reference. You can add as many <code>--range</code>&nbsp;and <code>--symbols</code>&nbsp;arguments as needed. Next, add the font size to generate with <code>--size</code>, the format with <code>--format</code>, the level of detail with <code>--bpp</code>, and a file path to output to with <code>-o</code>. The <a href="https://github.com/lvgl/lv_font_conv" rel="no follow" target="_blank">font converter github page</a> has more details on each of these parameters.</p>



<p class="wp-block-paragraph">&nbsp;<span style="font-family:arial;">Altogether, a call might look like the following:</span></p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">Bash</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly> lv_font_conv --font ARIALUNI.TTF

  --range 0x0000-0x017F

  --range 0x0400-0x04FF

  --symbols КАСБОЙ

 --font NotoSansArabic-Regulat.ttf

  --range 0x0600-0x06FF

  --range 0xFE70-0xFEFF

 --size 10 --format lvgl --bpp 3 -o examplefont.c</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">lv_font_conv</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">--font</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">ARIALUNI.TTF</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #DCDCAA">--range</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">0x0000</span><span style="color: #CE9178">-0x017F</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #DCDCAA">--range</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">0x0400</span><span style="color: #CE9178">-0x04FF</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #DCDCAA">--symbols</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">КАСБОЙ</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">--font</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">NotoSansArabic-Regulat.ttf</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #DCDCAA">--range</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">0x0600</span><span style="color: #CE9178">-0x06FF</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #DCDCAA">--range</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">0xFE70</span><span style="color: #CE9178">-0xFEFF</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">--size</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">10</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">--format</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">lvgl</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">--bpp</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">3</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">-o</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">examplefont.c</span></span></code></pre></div>



<pre class="wp-block-code"><code> </code></pre>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"><span style="font-family:arial;">Note that newlines and indentation are included for clarity, the only separator should be spaces since this is invoked from a command line. To that end, it’s helpful to store arguments in a text file, then parse them into calls in a script with something like bash’s <code>mapfile</code>&nbsp;command.</span></p>



<p class="wp-block-paragraph">Once a font has been generated, it can be included in the project, declared with <code>LV_FONT_DECLARE</code>, and used the same as LVGL’s default fonts.</p>



<h2 id="h-common-challenges" class="wp-block-heading">Common Challenges</h2>



<p class="wp-block-paragraph">What follows is a collection of some common challenges one might encounter when creating internationalized UIs, and some tips as to how they can be handled with&nbsp;the tools discussed here.</p>



<p class="wp-block-paragraph"><u><strong>Base Direction</strong></u></p>



<p class="wp-block-paragraph">Languages vary in their base directions; English, for example, is a left-to-right (LTR) language, while languages using the Arabic script are right-to-left languages (RTL). LVGL has some built-in handling for different base directions, namely the <code>base_dir</code>&nbsp;style property.</p>



<p class="wp-block-paragraph">When creating an object, it can be given a base direction with <code>lv_obj_set_style_base_dir</code>, or attaching a style with the property already set (by <code>lv_style_set_base_dir</code>). This will work in most cases, but, with strings containing both LTR and RTL languages, you may need to specify text direction manually. For this, one can use Unicode directional indicators. Including the following in your project will allow you to change direction within a string.</p>



<p class="wp-block-paragraph"><code>#define LRI "\xE2\x81\xA6"</code></p>



<p class="wp-block-paragraph"><code>#define RLI "\xE2\x81\xA7"</code></p>



<p class="wp-block-paragraph"><code>#define PDI "\xE2\x81\xA9"</code></p>



<p class="wp-block-paragraph">LRI indicates left-to-right, RLI the opposite, and PDI (pop directional indicator) undoes the most recent indicator. Wrapping chunks of text in LRI/RLI … PDI can be thought of as splitting the overall string into substrings, with the base direction of the overall string governing the order these substrings will appear. As an example, if the following string were to be placed in a label with RTL base direction:</p>



<p class="wp-block-paragraph">“&lt;LRI&gt;123&lt;PDI&gt; &lt;RLI&gt;456&lt;PDI&gt; &lt;LRI&gt;789&lt;PDI&gt;”</p>



<p class="wp-block-paragraph">(note: angle brackets included for clarity), it would appear on screen as</p>



<p class="wp-block-paragraph">“789 654 123”.</p>



<p class="wp-block-paragraph">Note also that LVGL may output warnings for missing glyph descriptions when rendering strings containing these characters. They are zero-width characters and function correctly regardless of whether they are included in the font, so these warnings can be safely ignored&nbsp;or suppressed in lv_conf.h (though missing glyph warnings are very helpful when working with custom fonts).</p>



<p class="wp-block-paragraph"><u><strong>Information Density</strong></u></p>



<p class="wp-block-paragraph">Languages vary in information density; three Chinese characters might convey the same information as twenty Latin ones in English or thirty in Spanish. As such, it’s helpful to leave extra space in screen layouts for languages less dense than the one being used for development.</p>



<p class="wp-block-paragraph">When this isn't possible, however, one can also use LVGL’s long text handling. Calling <code>lv_label_set_long_mode</code>&nbsp;will allow the developer to specify whether a label with text that does not fit in its width scrolls, wraps, or is cut off (optionally ending the displayed text with “…”) . Make sure to set the width of the label <u>after</u> calling this function.</p>



<p class="wp-block-paragraph">In cases where built-in long modes are not desirable, another option is to decrease font size. Using <code>lv_txt_get_size</code>&nbsp;to check whether a string will fit in a space with a given font, it’s possible to implement automatic font scaling&nbsp;(though the exact process will vary greatly from UI to UI depending on the desired behavior).</p>



<p class="wp-block-paragraph"><u><strong>Inserting Variables into Translated Text</strong></u></p>



<p class="wp-block-paragraph">One common use of text in a UI is to provide context for numerical information, which is complicated by the fact that translations need to be compiled beforehand. Thankfully, there’s a simple solution. As mentioned before, lv_i18n’s translation function&nbsp;<code>_( )</code> is a simple, direct replacement. This means that the translated string can be used with basic C text functions, namely <code>snprintf</code>. Including “%s” (or other format codes) in both the initial string and its translations will allow values to be inserted into the string by code after translation. When using this method, take care to allocate enough space in the buffer passed to <code>snprintf</code>&nbsp;for your longest translation.</p>



<p class="wp-block-paragraph">When a string contains multiple variable values, they can appear in different orders from language to language. This can be solved with either clever translation to keep fields in the same order, or by tracking which language is active and supplying arguments to <code>sprintf</code>&nbsp;in the corresponding order.</p>



<p class="wp-block-paragraph"><u><strong>Duplicate words</strong></u></p>



<p class="wp-block-paragraph">Languages often have words that&nbsp;mean several different things. As an example, an English UI might include the string “set” in multiple places, some using the word as a verb, others as a noun. These words don’t necessarily line up between languages, so the string “set” would likely need two translations in other languages. lv_i18n can only attach one translation to each original string per language, so this may initially seem like a significant issue, but the tool is perfectly capable of handling these situations.</p>



<p class="wp-block-paragraph">lv_i18n creates a lookup table for each language, mapping strings to other strings. The initial, untranslated strings scraped from your file are really just IDs to search translations by, and you can supply corresponding “translations” for them in your base locale (development language) just like any other language.</p>



<p class="wp-block-paragraph">Returning to the previous example with the word “set”, you can change the strings in your code to “set (v)” and “set (n)” and re-run <code>lv_i18n extract</code>. In the yml files belonging to other languages, fill in the translation for "set" as a noun next to “set (n)” and "set" as a verb next to “set (v)”. In “en.yml”, just place the word “set” next to both.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/duplicate_word_example.png" alt="Translation files implementing duplicate words"/></figure>



<p class="wp-block-paragraph">Re-run <code>lv_i18n compile</code>. Running the program in English, you should still see “set” everywhere, but changing the language will now show different translations for different uses of “set”.</p>



<p class="wp-block-paragraph"><strong>Learn More about DMC's <a href="/services/embedded-development-and-embedded-programming/embedded-user-interface-design">Embedded User Interface Design</a> services and <a href="/contact">contact us</a> today for your next project.</strong></p>



<p class="wp-block-paragraph"></p>
<p>The post <a href="https://static.dmcinfo.com/blog/17764/lvgl-for-international-gui-design/">LVGL for International GUI Design</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Advantages of .NET and Python for Test &#038; Measurement Applications</title>
		<link>https://static.dmcinfo.com/blog/18030/advantages-of-net-and-python-for-test-measurement-applications/</link>
		
		<dc:creator><![CDATA[Mark Locascio]]></dc:creator>
		<pubDate>Wed, 07 Dec 2022 16:57:14 +0000</pubDate>
				<category><![CDATA[LabVIEW]]></category>
		<category><![CDATA[PC Application Development]]></category>
		<category><![CDATA[Test and Measurement Automation]]></category>
		<category><![CDATA[User Interface Design]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/18030/advantages-of-net-and-python-for-test-measurement-applications/</guid>

					<description><![CDATA[<p>Prologue In May 2019, at what would become the last NI Week ever, I led a session called “Learning to Love Text Again With Measurement Studio.” It was scheduled for 8:30 AM on the last day of the conference, so I was surprised that so many travel-weary engineers stumbled in, red-eyed, with clumps of taco [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/18030/advantages-of-net-and-python-for-test-measurement-applications/">Advantages of .NET and Python for Test &#038; Measurement Applications</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 id="h-prologue" class="wp-block-heading">Prologue</h2>



<p class="wp-block-paragraph">In May 2019, at what would become the last NI Week ever, I led a session called “<a href="https://forums.ni.com/ni/attachments/ni/niweeksessions/425/11/Learning%20to%20Love%20Text%20Again%20With%20Measurement%20Studio_Software.pdf">Learning to Love Text Again With Measurement Studio</a>.” It was scheduled for 8:30 AM on the last day of the conference, so I was surprised that so many travel-weary engineers stumbled in, red-eyed, with clumps of taco still stuck in their hair, ready to listen to me talk about what&nbsp;I thought was a fairly niche topic. I was wrong! The room was filled with enthusiasm, although some of it was already about where to get lunch.</p>



<p class="wp-block-paragraph">It is now December 2022. NI Week is gone, but the Test &amp; Measurement community is still hungry for Austin’s spectacular tacos and alternative software development platforms. A mere three-and-a-half years later, I have finally found time to convert that presentation into a series of blog posts for those of you who weren’t there (or who slept through it). The intent is to motivate the use of Python or Microsoft’s .NET platform as programming environments for&nbsp;<a href="https://static.dmcinfo.com/services/test-and-measurement-automation">Test &amp; Measurement Automation</a>, and to provide you with some guidance toward getting started.</p>



<h2 id="h-introduction" class="wp-block-heading">Introduction</h2>



<p class="wp-block-paragraph">The purpose of this post is to describe the advantages of Python and .NET software development for Test &amp; Measurement applications. The <em>de facto</em> standard is generally National Instruments LabVIEW, due to the shallow learning curve and the quality and&nbsp;feature set of NI hardware; however, NI is also very good about offering hardware APIs for other languages&nbsp;— which gives you the flexibility to choose another option if it’s the right tool for the job. This post will describe why, in certain circumstances, the right tool may be Python or .NET.</p>



<p class="wp-block-paragraph">In a separate post, <a href="https://static.dmcinfo.com/latest-thinking/blog/id/10390/measurement-studio-net-programming-for-ni-enthusiasts">I also offer a brief overview of NI’s Measurement Studio</a>&nbsp;— which is a very useful set of tools that makes it easier for LabVIEW developers to get started with .NET.</p>



<p class="wp-block-paragraph">Measurement Studio offers:</p>



<ul class="wp-block-list">
<li>.NET classes and functions analogous to LabVIEW’s data analysis VIs</li>



<li>.NET data types analogous to those used by LabVIEW (e.g., analog and&nbsp;digital waveform types)</li>



<li>A .NET API for creating and managing TDMS files</li>



<li>Controls, indicators, and graph elements that can be used in .NET UIs</li>
</ul>



<p class="wp-block-paragraph">If I make a compelling case here and you’d like to try building your next Test &amp; Measurement application in .NET, I recommend getting started with the free trial of Measurement Studio. The familiar tools that it provides will help you leverage your existing LabVIEW knowledge to work efficiently in a new environment.</p>



<h2 id="h-strengths-of-labview-development" class="wp-block-heading">Strengths of LabVIEW Development</h2>



<p class="wp-block-paragraph">From the beginning, NI’s mission for LabVIEW was to make it easy for scientists and&nbsp;engineers to build Test &amp; Measurement applications. Since the mid-80s, the guiding principles of NI’s LabVIEW investment were to:</p>



<ul class="wp-block-list">
<li>Enable fast, easy software development</li>



<li>Make hardware integration as simple as possible</li>



<li>Provide a standard library with a focus on engineering functionality</li>



<li>Lower the barrier to producing graphical user interfaces</li>
</ul>



<p class="wp-block-paragraph">For these reasons, there are some use cases for which LabVIEW is an obvious win. If you need to get an application up and&nbsp;running quickly, if it needs to acquire, process, and visualize data, and if it will neither&nbsp;be deployed widely nor maintained for a very long time, then you will likely benefit from the productivity of developing in LabVIEW.</p>



<h2 id="h-where-can-we-do-better" class="wp-block-heading">Where Can We Do Better?</h2>



<p class="wp-block-paragraph">Larger projects require larger teams in order to meet delivery deadlines or maintain the software throughout its lifecycle. However, larger teams need to be able to work in parallel without stepping on each other’s toes. Beyond the initial delivery, maintaining the software can become a challenge as it ages and evolves&nbsp;and&nbsp;as developers drift in and&nbsp;out of the project. Here, we will discuss some advantages to Python and C# that reduce the complexity of maintaining a large software project throughout its lifecycle.</p>



<h3 id="h-enabling-technology" class="wp-block-heading">Enabling Technology</h3>



<p class="wp-block-paragraph">Oddly enough, the graphical nature of LabVIEW, which makes it one of the most beginner-friendly&nbsp;programming languages, also makes it extremely difficult to compare two pieces of code. It is easy to navigate and visually parse LabVIEW code, but very difficult to graphically represent <strong><em>the difference</em></strong> between two pieces of code.</p>



<p class="wp-block-paragraph">Consider the case in which you wrote a VI and shared it with a colleague. If that colleague edited it and gave you a new version, how would you find all of&nbsp;the differences? You can hunt them down on your own, but you’ll need to search every case structure and check the default value of every control. Even if it were a simple VI that could be visually compared easily, you’d have to identify each change as either functional or cosmetic (i.e., an additional wire bend is a difference, but an inconsequential one). <a href="https://labviewwiki.org/wiki/Set_up_differencing_capabilities" target="_blank">Some automated tools exist</a>, but they tend to be hard to configure and use. Furthermore, once all of the differences are identified, how do you visualize them concisely?</p>



<p class="wp-block-paragraph">Text source code is much more limited in terms of layout. It’s very easy for a computer to parse two chunks of text, compare them, and produce a simple visualization of the differences (often referred to as a “diff”). Simple as it may seem, this enables a substantial number of tools and techniques for managing source code that are not available for complex binary files like VIs. This is critical for code reviews as a quality assurance technique. Senior developers can easily review only the diffs, which are both concise and automatically generated.</p>



<h3 id="h-multi-developer-workflows" class="wp-block-heading">Multi-developer Workflows</h3>



<p class="wp-block-paragraph">Being able to see only the differences in two chunks of code is important for quality assurance, but it gets even better: a diff can also be used to easily merge changes into source code as well. This is a major enabler for multi-developer scenarios because it means that two or more developers can make changes to different parts of the same source file, and those changes can be blended together easily (i.e., they won’t collide unless there are different variations of the same lines of text).</p>



<p class="wp-block-paragraph">DMC’s platform of choice is <a href="https://about.gitlab.com/" target="_blank">GitLab</a>, which is a web-based software development management tool.</p>



<p class="wp-block-paragraph">GitLab provides:</p>



<ul class="wp-block-list">
<li>A revision-control system (<a href="https://git-scm.com/" target="_blank">git</a>)</li>



<li>Source code navigation, viewing, and comparing</li>



<li>Organized methods for users to track issues and resolutions</li>



<li>Automations for testing and building applications</li>



<li>Different user roles that enable better collaboration with both internal and&nbsp;external teams</li>



<li>Many other features</li>
</ul>



<p class="wp-block-paragraph">Of particular importance is the issue resolution workflow, which can be separated into individual workflows for different user roles, such as:</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/workflow_1.png" alt=""/></figure>



<p class="wp-block-paragraph">In this diagram, we have several people working in parallel (from top to bottom): a technical lead, a few developers, and anyone else with access to the source. Anyone with access to the source code repository can test the code and report issues (bottom). Developers (center) can select a reported issue, create a branch of code dedicated to its resolution, resolve the issue, and submit a “merge request.” The technical lead of the project (top) can then review those merge requests, ensure the code meets quality standards (by viewing the diff of that branch with the main line of development), and merge the updated code into the main line of development independently and in parallel with the developers.</p>



<p class="wp-block-paragraph">We have found that the cadence of code reviews is easier to maintain with this workflow. GitLab serves as a portal to view only the parts of the code that have changed and allows you to discuss those changes with the developer (asynchronously, via the web interface) before merging them. Instead of sitting down in a conference room and having the developer&nbsp; walk the technical lead through all the changes in a branch, the technical lead can simply view a diff those changes&nbsp;and enter comments or suggestions that the developer can then address later (as shown below). Once all comments have been addressed and the technical lead is satisfied with the changes, they can be merged.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/gitlab-diff.png" alt="The GitLab comparison tool shows the source code diff and allows a code reviewer to leave comments &amp; questions for the code's author."/></figure>



<p class="wp-block-paragraph">This substantially improves the code review workflow, allowing the tech lead and developers to work asynchronously, communicate effectively, and collaborate productively.</p>



<h3 id="h-separation-of-concerns" class="wp-block-heading">Separation of Concerns</h3>



<p class="wp-block-paragraph">One objective of good software design is “separation of concerns.” One must break down the problem into smaller and smaller problems, and then those into <strong><em>even smaller</em></strong> problems, continuing until there is a tree of convenient fun-size problems that can each be solved easily. Implicit in this methodology is the idea that each problem should be independent of the others. The programmer should establish clear interfaces between problems to keep them logically separate.</p>



<p class="wp-block-paragraph">If you haven’t heard of SOLID design principles, consider <a href="https://static.dmcinfo.com/latest-thinking/blog/id/10019/dmc-attends-2019-national-instruments-cla-summit">reading through a blog post</a> by my colleague and LabVIEW <em>aficionado</em> <a href="https://static.dmcinfo.com/about/employee-bios/steven-dusing">Steven Dusing</a>. The “S” in SOLID stands for “single responsibility,” meaning that, as you separate your concerns into smaller, more manageable problems, you should end up with chunks of code that do one thing and one thing <strong><em>only</em></strong>.</p>



<p class="wp-block-paragraph">If different pieces of code are truly separated, you can even delegate them to people with different skill sets. Wouldn’t it be nice to have a UI designer handle the graphical layout of your application while engineers develop the business logic? A LabVIEW VI has a user interface (front panel) that is inextricably tied to the business logic (block diagram). This makes it dirt-simple to produce a GUI application, but it also&nbsp;makes it very hard to have a complex UI that is separate from the business logic and can be developed by a different person.</p>



<p class="wp-block-paragraph">As an example, consider <a href="https://learn.microsoft.com/en-us/dotnet/desktop/wpf/?view=netdesktop-6.0">WPF</a>, one of the graphical frameworks available on the .NET platform. The UI layout is specified with <a href="https://learn.microsoft.com/en-us/dotnet/desktop/wpf/xaml/?view=netdesktop-6.0" target="_blank">an XML-style language</a> completely separately from the run-time logic. Since the graphical layout is specified as a text language, diffs are supported for easy review, and, since it exists in its own file, your UI/UX designer can work in parallel with the engineering team. We have effectively separated our concerns: UI things get handled in a UI file by a UI expert, and business logic things get handled in C# code by C# experts.</p>



<p class="wp-block-paragraph">Outside of the .NET framework, various graphical toolkits are available&nbsp;but&nbsp;my personal preference is <a href="https://www.qt.io/" target="_blank">Qt</a>&nbsp;—&nbsp;which is available under the terms of the LGPL (mostly). Qt provides QML, which is conceptually similar to XAML (i.e., like XAML, QML is a declarative UI description language), and gets used in the same way to separate your UI design from business logic. Business logic can be implemented in Python, C++, or some other languages with third-party bindings to Qt.</p>



<h3 id="h-best-practices-for-software-development" class="wp-block-heading">Best Practices for Software Development</h3>



<p class="wp-block-paragraph">In LabVIEW 8.2, object-oriented design principles were introduced to LabVIEW, which was a difficult balancing act. NI’s team aimed to make Object-Oriented Programming (OOP) accessible to scientists and engineers who didn’t necessarily have a computer scientist’s background, without compromising the fundamentals on which LabVIEW was built.</p>



<p class="wp-block-paragraph"><a href="https://www.ni.com/en-us/support/documentation/supplemental/06/labview-object-oriented-programming--the-decisions-behind-the-de.html" target="_blank">This was done out of a recognition that</a>:</p>



<blockquote class="is-layout-flow wp-block-quote-is-layout-flow">

<p class="wp-block-paragraph">Object-oriented programming has demonstrated its superiority over procedural programming as an architecture choice in several programming languages. It encourages clear divisions between sections of the code, it is easier to debug, and it scales better for large programming teams. LabVIEW R&amp;D wanted this power to be accessible by our customers. We wanted the language to be able to enforce some of these software best-practices.</p>


</blockquote>



<p class="wp-block-paragraph">There are a lot of compelling reasons to use an object orientation (OO) approach, and NI needed to balance that with the need to maintain the concept of dataflow, and a recognition that this might not be the right approach for every person, every project, and every situation. Consequently, the implementation of OO in LabVIEW is very useful and&nbsp;very easy to use, but it is substantially different from traditional OO. For larger projects with larger teams, leveraging the scalability and modularity of a truly object-oriented language can lead to a better product and a more efficient development experience.</p>



<h3 id="h-deployment" class="wp-block-heading">Deployment</h3>



<p class="wp-block-paragraph">The three languages we’ve been discussing most (LabVIEW, C#, and Python) all need to run in the context of some set of libraries on the target machine. That may be the LabVIEW Runtime Engine, the .NET Framework, or the Python interpreter, respectively.</p>



<p class="wp-block-paragraph">Applications that will be widely distributed will generally benefit from the fact that all Windows installations either have the .NET runtime installed already, or they make it easy to do so automatically. Python even has the advantage of creating virtual environments&nbsp;which allow multiple Python interpreters to co-exist on a system, and for each project to have its own set of dependencies installed without any of them colliding with the others. Virtual environments are important for development, but they can also be used to ensure that applications are installed consistently across various systems.</p>



<p class="wp-block-paragraph">For large development projects, the deployment procedure should be considered early. In many cases, the .NET framework is already installed and available on Windows machines, and if the target will be Linux, Python is widely available and often distributed by default with an OS installation.</p>



<h3 id="h-community-support-and-nbsp-engagement" class="wp-block-heading">Community Support and&nbsp;Engagement</h3>



<p class="wp-block-paragraph">The largest and most active development communities generally produce some of the most useful third-party tools,&nbsp;often under open-source license terms. Based on the relatively informal <a href="https://www.tiobe.com/tiobe-index/">TIOBE index</a>, both C# and Python land in the top 5 most searched programming languages. Using that as a proxy for the activity of their respective communities, it is not surprising that the package managers for these platforms runneth over with useful tools and libraries that can be readily used in your projects.</p>



<p class="wp-block-paragraph">The .NET framework provides a package management system called <a href="https://www.nuget.org/" target="_blank">NuGet</a>, which currently hosts over 330,000 unique packages. For Python, the pip module is used to connect to <a href="https://pypi.org/" target="_blank">pypi</a> (over 420,000 unique packages) or other package repositories. While LabVIEW does have both JKI’s VI Package Manager (with over 1000 packages) and NI’s own package manager, neither offers the same level of community engagement.</p>



<p class="wp-block-paragraph">As projects get larger, the availability and quality of reusable tools and&nbsp;libraries can help drive down the amount of code you need to maintain yourself.</p>



<h2 id="h-summary" class="wp-block-heading">Summary</h2>



<p class="wp-block-paragraph">In recent years, NI has made substantial investments in support for .NET and Python. While LabVIEW continues to be a good option for some Test &amp; Measurement applications, many (particularly large projects) could benefit from different tools.</p>



<p class="wp-block-paragraph">For some engineers, the learning curve of training up on a language other than LabVIEW may be prohibitive. In these cases, I recommend considering NI Measurement Studio as a stepping stone. Read <a href="https://static.dmcinfo.com/latest-thinking/blog/id/10390/measurement-studio-net-programming-for-ni-enthusiasts" type="link" id="https://static.dmcinfo.com/latest-thinking/blog/id/10390/measurement-studio-net-programming-for-ni-enthusiasts">my overview</a> of how Measurement Studio can fill the gaps between LabVIEW and C#.</p>



<p class="wp-block-paragraph"><strong>Learn more about DMC&#8217;s <a href="https://static.dmcinfo.com/services/test-and-measurement-automation">Test &amp; Measurement Automation solutions</a>, and <a href="https://static.dmcinfo.com/contact">contact us</a> today for your next project.</strong></p>



<p class="wp-block-paragraph"></p>
<p>The post <a href="https://static.dmcinfo.com/blog/18030/advantages-of-net-and-python-for-test-measurement-applications/">Advantages of .NET and Python for Test &#038; Measurement Applications</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>5 Advanced UI Design Hacks for Beginners</title>
		<link>https://static.dmcinfo.com/blog/20580/5-advanced-ui-design-hacks-for-beginners/</link>
		
		<dc:creator><![CDATA[DMC]]></dc:creator>
		<pubDate>Fri, 08 Nov 2019 15:19:15 +0000</pubDate>
				<category><![CDATA[Application Development]]></category>
		<category><![CDATA[User Interface Design]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/20580/5-advanced-ui-design-hacks-for-beginners/</guid>

					<description><![CDATA[<p>As a UX/UI Designer, there are so many tips and tricks I wish I knew from the start. Several quick little “quality of life things” that I know now would have sped up my workflow and improved my designs. These things often come from experience and having good mentors around you. If you need some [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/20580/5-advanced-ui-design-hacks-for-beginners/">5 Advanced UI Design Hacks for Beginners</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">As a UX/UI Designer, there are so many tips and tricks I wish I knew from the start. Several quick little “quality of life things” that I know now would have sped up my workflow and improved my designs. These things often come from experience and having good mentors around you.</p>



<p class="wp-block-paragraph">If you need some tips and tricks ASAP, then you came to the right blog. Here are five advanced design hacks for beginners written by an&nbsp;intermediate.</p>



<h2 class="wp-block-heading" id="h-tip-1">Tip #1</h2>



<p class="wp-block-paragraph"><span style="font-size:130%;"><strong>Don’t waste time creating multiple shades of black. Use an opacity slider instead.</strong></span></p>



<p class="wp-block-paragraph">Whether creating a poster, user interface, or a simple presentation, using different shades of black for text will be necessary. Instead of consistently using your color picker to select new colors, why not try different shades of black over a white background.</p>



<p class="wp-block-paragraph">Using pure shades of black (#000000) causes eye strain for readers over long periods of time. It is best to use a slightly “off-black” color as your absolute black. Instead of color picking three or more hex color values, use black with different opacity as a solution.</p>



<p class="wp-block-paragraph">In the example below, I used my “off-black” as my primary color and decreased its opacity depending to where it will be applied (i.e., primary content, secondary content, tertiary content)</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Shades-of-Black.png" alt=""/></figure>



<h2 class="wp-block-heading" id="h-tip-2">Tip #2</h2>



<p class="wp-block-paragraph"><span style="font-size:130%;"><strong>Use color, font weight, and spacing to create hierarchy within your design.</strong></span></p>



<p class="wp-block-paragraph"><strong>Color and Weight</strong></p>



<p class="wp-block-paragraph">A common mistake when styling text for a UI or any piece of design is relying too much on font size to control your hierarchy.</p>



<p class="wp-block-paragraph">Instead of leaving all&nbsp;the heavy lifting to font size alone, a good trick is to use color or font weight to do the same job. If this bit of text is so important, it&#8217;s better to make it bolder, not bigger. This technique increases the text&#8217;s visual prominence and contrast without drastically increasing its overall footprint on the page.</p>



<p class="wp-block-paragraph">Two font weights are usually enough for UI work: A normal (Regular) font-weight for most body copy type text, and&nbsp;a heavier (Bold) font-weight for the text you want to emphasize (headlines).</p>



<p class="wp-block-paragraph">You may want to stay away from any font labeled “Light” or “Thin.” I’ve made this mistake several times and had to&nbsp;correct it. If you want to de-emphasize some text use a lighter color or smaller font size instead of a thinner weight.</p>



<p class="wp-block-paragraph">As for color, try and to stick to two or three colors in your UI design:</p>



<ul class="wp-block-list">
<li>A dark color (i.e., for primary content, like the headline of an article)</li>



<li>A grey for secondary content (i.e., body paragraph copy or descriptive text below the headline)</li>



<li>A lighter grey for a tertiary copy (i.e., the date an article was published on or a location tag).</li>
</ul>



<p class="wp-block-paragraph">These two tips will help create a more clearly defined hierarchy within your designs without falling into the common pitfalls when trying to do so.</p>



<p class="wp-block-paragraph">Now that you have your content styled correctly, it’s time to space everything out and solidify the user experience.&nbsp;</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Hierarchy-1.png" alt=""/></figure>



<p class="wp-block-paragraph"><strong>Spacing</strong></p>



<p class="wp-block-paragraph">There are many actions you can take to group UI elements. Using a generous space between objects is a fast, simple, and easy to implement solution. One of the fundamentals rules of UX Design, <a href="https://lawsofux.com/law-of-proximity/" target="_blank" rel="noreferrer noopener">the Law of Proximity</a>, states that objects that are closer together spatially tend to be grouped together.</p>



<p class="wp-block-paragraph">In this example,&nbsp;we can see that by moving and grouping elements together with white space, we can more easily create groups and eliminate the need for boxes or rule elements. This approach creates a cleaner design and one that is easier for your developers to implement.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Hierarchy-2_1.png" alt=""/></figure>



<h2 class="wp-block-heading" id="h-tip-3">Tip #3</h2>



<p class="wp-block-paragraph"><span style="font-size:130%;"><strong>Use color to separate lists, dropdowns, and table components instead of rule elements.</strong></span></p>



<p class="wp-block-paragraph">Creating rows and columns in any setting, for any component, can be a tedious and boring task at times. From a user’s perspective, however, a well-designed list, table, or drop menu can make an experience easier to use and more rewarding.</p>



<p class="wp-block-paragraph">Common issues with row-based components include difficulty reading, losing your place on a particular line, or getting information confused and mismatched.</p>



<p class="wp-block-paragraph">Instead of using lines and strokes to divide rows, try a colored background instead. This approach makes each line unique compared to the ones on top and below it. Making this cosmetic decision gets two birds with one stone as it eliminates users&#8217; pain points and makes the component more visually pleasing.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/05_Rule-Elements-1.png" alt="rule elements 2 "/></figure>



<p class="wp-block-paragraph">&nbsp;</p>



<h2 class="wp-block-heading" id="h-tip-4">Tip #4</h2>



<p class="wp-block-paragraph"><strong><span style="font-size:130%;">Avoid huge blocks of color. Instead, use small pops of color to spice up and accent a bland design.&nbsp;</span></strong></p>



<p class="wp-block-paragraph">People often turn to photography, iconography, or a complex digital illustration to bring visual flair to their designs (if you’ve explored <a href="https://dribbble.com/" target="_blank">Dribble</a> recently, you’ll know what I’m talking about). Instead, a simple trick&nbsp;many other designers and I use is to add a colorful accent to part of your interface that would otherwise feel a bit bland. Rather than&nbsp;adding huge blocks of color and going visually overboard, small accents of color can go a long way and exemplify restraint.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Accent-Color-1.png" alt="color accents"/></figure>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Accent-Color-2.png" alt="accent color 2"/></figure>



<p class="wp-block-paragraph">Have a hard time picking colors? Try using <a href="https://coolors.co/" target="_blank">coolors.co</a>.&nbsp;The color picker is flexible and easy to use. Their UI makes it easy to pick one color and build the rest of the palette around it, which is a feature I really like.&nbsp;</p>



<h2 class="wp-block-heading" id="h-tip-5">Tip #5</h2>



<p class="wp-block-paragraph"><strong><span style="font-size:130%;">Not every button needs a background color and a rounded corner.</span></strong></p>



<p class="wp-block-paragraph">What would a user interface be without buttons? There are many different styles you can add to your button. When I first started designing user interfaces, I approached buttons with a very semantic-heavy thought process.&nbsp;</p>



<p class="wp-block-paragraph">For example, if I needed to design a &#8220;start process&#8221; button, I would make it green. If I needed a &#8220;stop&#8221; button, I would make it red.&nbsp;</p>



<p class="wp-block-paragraph">Avoid this trope by dividing buttons styles into a more critical factor: hierarchy of importance (i.e., primary, secondary, and tertiary actions).</p>



<p class="wp-block-paragraph">Primary actions should be distinct. Solid, high contrast background colors. Secondary actions should be clearly defined, but not the most prominent. Outline styles or lower contrast background colors are great options. Tertiary actions should be discoverable but unobtrusive. Styling these actions as links is good approach.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Button-Types-Destructive-1.png" alt="button types"/></figure>



<p class="wp-block-paragraph"><strong>Destructive does not always = Red</strong></p>



<p class="wp-block-paragraph">If a&nbsp;destructive action isn’t the primary action on the page, it might be better to give to make it a more secondary or tertiary action look. A destructive button that is the primary action on the page or dialog is worthy of the big, red, bold button. See the examples below.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/Button-Types-Destructive-2.png" alt=""/></figure>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/10_Button-Types-Destructive.png" alt=""/></figure>



<p class="wp-block-paragraph">I hope these “5 Advanced UI Design Hacks for Beginners” were helpful and get you thinking about new ways to approach the decisions you have to make every day as a UX/UI designer. I’m sure you would have discovered these on your own in time, but I’m glad you decided to do your research and streamline the process.</p>



<p class="wp-block-paragraph"><strong>Learn more about <a href="/services/application-development/user-interface-design">DMC’s UX/UI Design Services</a>.</strong></p>
<p>The post <a href="https://static.dmcinfo.com/blog/20580/5-advanced-ui-design-hacks-for-beginners/">5 Advanced UI Design Hacks for Beginners</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Android 10 Logo &#038; Identity Review</title>
		<link>https://static.dmcinfo.com/blog/20895/android-10-logo-identity-review/</link>
		
		<dc:creator><![CDATA[DMC]]></dc:creator>
		<pubDate>Wed, 02 Oct 2019 11:47:28 +0000</pubDate>
				<category><![CDATA[Application Development]]></category>
		<category><![CDATA[User Interface Design]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/20895/android-10-logo-identity-review/</guid>

					<description><![CDATA[<p>History Android Inc. was founded in&#160;Palo Alto, California in October 2003 by&#160;Andy Rubin,&#160;Rich Miner, Nick Sears, and Chris White. Soon after its creation, it was acquired by Google in 2005, and first released to the public in 2008. Android is a mobile operating system for smartphones, tablets, and other connected devices. It is based on [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/20895/android-10-logo-identity-review/">Android 10 Logo &#038; Identity Review</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 id="h-history" class="wp-block-heading">History</h2>



<p class="wp-block-paragraph">Android Inc. was founded in&nbsp;Palo Alto, California in October 2003 by&nbsp;Andy Rubin,&nbsp;Rich Miner, Nick Sears, and Chris White. Soon after its creation, it was acquired by Google in 2005, and first released to the public in 2008. Android is a mobile operating system for smartphones, tablets, and other connected devices. It is based on a modified version of the&nbsp;Linux and other open source software. The platform is free to download, distribute, and modify.</p>



<p class="wp-block-paragraph">There are thousands of different phones and tablets from companies such as Samsung, Huawei, One Plus, and LG that use some version of Android as their operating system. Roughly 3 billion people around the world use android. It is, by far the most used mobile device software.</p>



<p class="wp-block-paragraph">Android 10 is the tenth major iteration of the software and also marks the move away from the <a href="https://www.computerworld.com/article/3235946/android-versions-a-living-history-from-1-0-to-today.html" target="_blank">unique naming convention</a> Android previously used. Along with the name change comes a major shift in the logo and identity of Android. This is bound to turn some heads and upset some hardcore fans. Let&#8217;s take a look at the new identity created by Brooklyn born design studio, <a href="https://www.hugeinc.com/" target="_blank">Huge</a>.</p>



<p class="wp-block-paragraph"><iframe loading="lazy" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" frameborder="0" height="315" src="https://www.youtube.com/embed/l2UDgpLz20M" width="560"></iframe></p>



<p class="wp-block-paragraph"><span style="”font-size:12px;"><em>New Identity Intro Video<br>
Video&nbsp;credit to: <a href="https://www.youtube.com/watch?v=l2UDgpLz20M&amp;t=1s" target="_blank">Android</a></em></span></p>



<h2 id="h-about-the-identity" class="wp-block-heading">About the Identity</h2>



<p class="wp-block-paragraph">In a recent <a href="https://www.blog.google/products/android/evolving-android-brand/">blog post</a>, Sameer Samat, VP of Product Management at Android, was quoted saying, &#8220;This year, we&#8217;re introducing a more modern, accessible look. The design of the logo draws inspiration from the most recognizable non-human member of the community, the Android robot. The robot belongs to everyone in the community and has been a symbol of the fun and curiosity at the heart of Android. Now, it has a special place in our logo.&#8221;</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/logo-on-white.jpg" alt=""/></figure>



<p class="wp-block-paragraph"><span style="”font-size:12px;"><em>Logo on White<br>
Image credit to: <a href="https://www.hugeinc.com/work/android" target="_blank">Huge Inc.</a> </em></span></p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/logo-on-dark.jpg" alt=""/></figure>



<p class="wp-block-paragraph"><span style="”font-size:12px;"><em>Logo on Dark<br>
Image credit to: <a href="https://www.hugeinc.com/work/android" target="_blank">Huge Inc.</a></em></span></p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/alternate-lockup.jpg" alt=""/></figure>



<p class="wp-block-paragraph"><span style="”font-size:12px;"><em>Alternate Logo Lockups<br>
Image credit to: <a href="https://www.hugeinc.com/work/android" target="_blank">Huge Inc.</a> </em></span></p>



<p class="wp-block-paragraph">The full-bodied robot has become so well-known and symbolic of Android that it is hard to see them ever fully moving away from it. However, the logo did have its flaws. The color, the size, and wordmark all had their own quirks, which made the identity feel dated and less mature than this new refreshed version. The new robot head works amazingly well as an icon. We’re so familiar with the full-bodied version that reducing it down to just the head makes perfect sense. Users still understand the context, the logo is more compact, reduces to a smaller size more easily, and is far more charming.&nbsp;The facial expressions of the robot itself are more playful and better executed than previous robot expressions.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/expressions.jpg" alt=""/></figure>



<p class="wp-block-paragraph"><span style="”font-size:12px;"><em>Icon Expressions<br>
Image credit to: <a href="https://www.hugeinc.com/work/android" target="_blank">Huge Inc.</a> </em></span></p>



<p class="wp-block-paragraph">The old wordmark was my least favorite part of the entire Android brand. The combination of all upper-case letters and the wide-open “D’s” was painful for designers all around. The new logo font is much better. A basic geometric San Serif set in either black or white, it is&nbsp;interesting and fits the aesthetic of the brand well.</p>



<p class="wp-block-paragraph">Lastly, the new green is a considerable improvement, with a more vibrant hue that is unique and energizing. Once again, Sameer Samat, “We also changed the logo (wordmark to be more specific) from green to black. It’s a small change, but we found the green was hard to read, especially for people with visual impairments.”</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/color-scheme.jpg" alt=""/></figure>



<p class="wp-block-paragraph"><span style="”font-size:12px;"><em>Color Scheme<br>
Image credit to: <a href="https://www.hugeinc.com/work/android" target="_blank">Huge Inc.</a> </em></span></p>



<p class="wp-block-paragraph">The new logo may upset some Android fans as it makes drastic changes to the robot and the wordmark. I think it is undeniable that this new logo is so much better and pleasing for a designer.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/typography_1.jpg" alt=""/></figure>



<p class="wp-block-paragraph"><span style="”font-size:12px;"><em>Typography<br>
Image credit to: <a href="https://www.hugeinc.com/work/android" target="_blank">Huge Inc.</a> </em></span></p>



<p class="wp-block-paragraph">I like the new typeface as it reminds me of other popular fonts such as Helvetica, Gotham, and Proxima Nova.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/identity-elements.jpg" alt=""/></figure>



<p class="wp-block-paragraph"><span style="”font-size:12px;"><em>Digital Advertising Collateral<br>
Image credit to: <a href="https://www.hugeinc.com/work/android" target="_blank">Huge Inc.</a> </em></span></p>



<p class="wp-block-paragraph">Print and digital collateral looks fresh and bright. Huge went with these pill, button-like shapes in both stroked and filled styles. While fairly basic, these match the full visual language of Android and the UI associated with the operating system itself.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/ui-examples.jpg" alt=""/></figure>



<p class="wp-block-paragraph"><span style="”font-size:12px;"><em>UI Examples<br>
Image credit to: <a href="https://www.hugeinc.com/work/android" target="_blank">Huge Inc.</a></em></span></p>



<h2 id="h-final-thoughts" class="wp-block-heading">Final Thoughts</h2>



<p class="wp-block-paragraph">Overall, I find the update lively, exciting, and maturation of the Android brand. The old identity fit the first few iterations of Android perfectly. In the early days, not only was Android new, the technology, smartphone, and connected device landscape was nowhere near as advanced as it is today. The logo always gave me the impression Android was for developers, programmers, and the tech-savvy. Digital collateral from that time feels almost nostalgic now.</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/old-developer-robot-2.jpg" alt=""/></figure>



<p class="wp-block-paragraph"><span style="”font-size:12px;"><em>Old Android Developer Artwork&nbsp;<br>
Image credit to: <a href="https://www.androidguys.com/news/android-development-starting-from-scratch/" target="_blank">Android Guys</a></em></span></p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/old-digital-ad.jpg" alt=""/></figure>



<p class="wp-block-paragraph"><span style="”font-size:12px;"><em>Android Oreo Artwork<br>
Image credit to: <a href="https://www.gsmarena.com/google_android_through_the_years-news-31123.php" target="_blank">GSM Arena</a></em></span></p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/old-developer-robot.jpg" alt=""/></figure>



<p class="wp-block-paragraph"><span style="”font-size:12px;"><em>Old Android Developer Logo<br><br>Image credit to: <a href="https://www.xda-developers.com/linkedin-google-android-developer-certification/" target="_blank">XDA Developers</a></em></span></p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/old-robot-costumes.jpg" alt=""/></figure>



<p class="wp-block-paragraph"><span style="”font-size:12px;"><em>Old Android Robot Costumes<br> Image credit to: The New York Times</em></span></p>



<p class="wp-block-paragraph">Android had got to a point where it outgrew the old branding. Now that both the technology and industry is well established, the branding can focus less on the developer community and more on the consumers themselves. This new logo is a logical step forward for a company that keeps innovating year after year. Huge did a fabulous job with this redesign and has set up Android for even more future success.</p>



<p class="wp-block-paragraph">Learn more about <a href="https://static.dmcinfo.com/services/application-development/user-interface-design" type="link" id="https://static.dmcinfo.com/services/application-development/user-interface-design">DMC’s UX/UI Design Services</a>.</p>
<p>The post <a href="https://static.dmcinfo.com/blog/20895/android-10-logo-identity-review/">Android 10 Logo &#038; Identity Review</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>User Interface Design Tips: Checkboxes vs Toggle Switches</title>
		<link>https://static.dmcinfo.com/blog/22434/user-interface-design-tips-checkboxes-vs-toggle-switches/</link>
		
		<dc:creator><![CDATA[DMC]]></dc:creator>
		<pubDate>Tue, 27 Nov 2018 15:50:10 +0000</pubDate>
				<category><![CDATA[User Interface Design]]></category>
		<category><![CDATA[Design]]></category>
		<category><![CDATA[UI/UX]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/22434/user-interface-design-tips-checkboxes-vs-toggle-switches/</guid>

					<description><![CDATA[<p>Interactivity, or input from a user, is expected in almost every type of mobile or desktop application, website, or interface. Users enter personal information, change application settings, and navigate various menus while using&#160;an interface. As designers, it is our job to provide users with the correct controls to make these inputs easier and quicker. Two [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/22434/user-interface-design-tips-checkboxes-vs-toggle-switches/">User Interface Design Tips: Checkboxes vs Toggle Switches</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph">Interactivity, or input from a user, is expected in almost every type of mobile or desktop application, website, or interface. Users enter personal information, change application settings, and navigate various menus while using&nbsp;an interface. As designers, it is our job to provide users with the correct controls to make these inputs easier and quicker.</p>

<p class="wp-block-paragraph">Two of the most common controls, toggle switches and checkboxes, appear to accomplish the same task and often get their use cases confused as a result. However, there are very specific instances where you should use one or the other. This blog will explain the differences between checkboxes and toggle switches and identify when to use each in your user interfaces.&nbsp;</p>

<h4 class="wp-block-heading">Distinguishing Between Checkboxes&nbsp;and Toggle Switches</h4>

<p class="wp-block-paragraph">A&nbsp;<strong>checkbox</strong>&nbsp;control has two states: unselected and selected. Checkboxes should be utilized&nbsp;when a user can choose any number of listed options. Checkboxes will usually require buttons such as &ldquo;Submit, OK, Next, Apply&rdquo; after the boxes have been checked.</p>

<p class="wp-block-paragraph">A&nbsp;<strong>toggle&nbsp;</strong><strong>switch</strong> represents a physical switch and is an &ldquo;either/or&rdquo; control that allows users to turn things on or off, like a light switch. Similar to flipping a light switch, the effects of that switch are felt immediately. This same characteristic applies to UI toggle switches.</p>

<p class="wp-block-paragraph">Switches can provide an added benefit to mobile users. Switches have a larger touchpoint to connect with and can provide more haptic feedback compared to checkboxes.</p>

<p class="wp-block-paragraph">Tapping a toggle switch is a two-step action: selection and execution, whereas a checkbox is just selection of an option and the execution/saving action is usually required later on or is in a separate location.</p>

<p class="wp-block-paragraph">Below are few use-cases to help you decide which control is right for your user interface.</p>

<h4 class="wp-block-heading">When to Use a Toggle Switch</h4>

<ul class="wp-block-list">
 <li>An instant response is required without review or confirmation.&nbsp;</li>
 <li>A setting requires an on/off or show/hide function.</li>
</ul>

<p class="wp-block-paragraph">&nbsp;<img decoding="async" alt="When to use a toggle switch in your UI" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/DarkMode-Gif.gif"  /></p>

<h4 class="wp-block-heading">When to Use Checkboxes</h4>

<ul class="wp-block-list">
 <li>Options need to be confirmed or reviewed by the user before they are submitted.</li>
 <li>The user has to perform additional steps for changes to become active.</li>
</ul>

<p class="wp-block-paragraph"><img decoding="async" alt="When to use checkboxes in design" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/checkbox-01.jpg"  />&nbsp;<img decoding="async" alt="When to use checkboxes in your UI" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/checkbox-02.jpg"  /></p>

<ul class="wp-block-list">
 <li>Multiple options are available, and the user has to select one or more options from them.</li>
</ul>

<p class="wp-block-paragraph"><img decoding="async" alt="When to use a checkbox" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/checkbox-03.jpg"  />&nbsp;<img decoding="async" alt="When to use a checkbox" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/checkbox-04.jpg"  /></p>

<ul class="wp-block-list">
 <li>A single yes/no choice is provided, or only one option can be selected, and its meaning is obvious.</li>
</ul>

<p class="wp-block-paragraph"><img decoding="async" alt="Using a checkbox in design" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/checkbox-05.jpg"  />&nbsp;<img decoding="async" alt="Using a checkbox in design" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/checkbox-06.jpg"  /></p>

<ul class="wp-block-list">
 <li>The user is toggling independent features or behaviors, and you want to offer two options for an on/off type of decision.</li>
</ul>

<p class="wp-block-paragraph"><img decoding="async" alt="Best practices for checkboxes in design" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/checkbox-07.jpg"  />&nbsp;<img decoding="async" alt="Best practices for UI checkboxes" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/checkbox-08.jpg"  /></p>

<h4 class="wp-block-heading">Conclusion</h4>

<p class="wp-block-paragraph">When deciding between a switch or checkbox, focus on context, not function. Ask yourself whether a setting should take immediate effect or not. Ask yourself whether users need to check their settings before they apply them.</p>

<p class="wp-block-paragraph"><strong>Learn more about DMC&apos;s <a href="https://static.dmcinfo.com/services/application-development/user-interface-design">User Interface Design expertise.</a></strong></p>
<p>The post <a href="https://static.dmcinfo.com/blog/22434/user-interface-design-tips-checkboxes-vs-toggle-switches/">User Interface Design Tips: Checkboxes vs Toggle Switches</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>DMC Attends Inaugural TwinCAT HMI Training</title>
		<link>https://static.dmcinfo.com/blog/22685/dmc-attends-inaugural-twincat-hmi-training/</link>
		
		<dc:creator><![CDATA[DMC]]></dc:creator>
		<pubDate>Mon, 17 Sep 2018 10:33:52 +0000</pubDate>
				<category><![CDATA[HMI and SCADA]]></category>
		<category><![CDATA[Manufacturing Automation & Intelligence]]></category>
		<category><![CDATA[PLC]]></category>
		<category><![CDATA[User Interface Design]]></category>
		<category><![CDATA[Web Application Development]]></category>
		<category><![CDATA[Beckhoff and TwinCAT]]></category>
		<category><![CDATA[HTML and CSS]]></category>
		<category><![CDATA[MS Visual Studio/.NET]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Web]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/22685/dmc-attends-inaugural-twincat-hmi-training/</guid>

					<description><![CDATA[<p>Earlier this year, DMC attended a training course on the new TwinCAT HMI at Beckhoff&#8217;s U.S. headquarters in Savage, MN. We were impressed by the flexibility and convenience offered by the platform and have already enjoyed using it on projects. Due to its unique developer-friendly design, DMC has been able to reduce development time and [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/22685/dmc-attends-inaugural-twincat-hmi-training/">DMC Attends Inaugural TwinCAT HMI Training</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph">Earlier this year, DMC attended a training course on the new TwinCAT HMI at Beckhoff&rsquo;s U.S. headquarters in Savage, MN. We were impressed by the flexibility and convenience offered by the platform and have already enjoyed using it on projects. Due to its unique developer-friendly design, DMC has been able to reduce development time and save money for our clients. Here&rsquo;s a couple of the features of Beckhoff&rsquo;s new HMI that set it apart:</p>

<p class="wp-block-paragraph"><strong>Web-based Control and Monitoring</strong></p>

<p class="wp-block-paragraph">The most appealing aspect of Beckhoff&rsquo;s platform is that it leverages the internet to allow end users to control and monitor their PLCs from anywhere. Interfacing with industrial controllers via the internet is a common request for DMC, and the TwinCAT HMI makes this easier than ever before with integrated server- and client-side development connecting easily to the underlying PLC access. The key benefit is that a web-based HMI can be accessed from any number of different clients &ndash; a traditional monitor screen nearby the device being controlled, a tablet carried around the area by a supervisor, or even a mobile phone halfway around the world. The HMI includes a responsive grid designed to facilitate development for multiple device sizes.</p>

<figure class="wp-block-image"><img decoding="async" alt="Multiple Web Clients for TwinCAT HMI Server" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/TCHMI-Multi-Client_1.jpg"  /></figure>

<p class="wp-block-paragraph"><strong>WYSIWYG Web Page Design</strong></p>

<p class="wp-block-paragraph">As any web developer can tell you, managing the location and arrangement of content on the page can be one of the most time-consuming aspects to do manually. Development for TwinCAT gets around these issues using a What You See Is What You Get style editor, paired with other features to make life easy for developers. Selecting and arranging components is as simple as dragging them in from a menu. The HMI features dozens of prebuilt components, including commonly used displays and controls, as well as advanced charts. We walked through a demo project using several different charts, which update live when linked with the PLC data, making it very easy to display live system data of all sorts to your end users.</p>

<figure class="wp-block-image"><img decoding="async" alt="TwinCAT HMI Development in Visual Studio" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/TCHMI-VS.jpg"  /></figure>

<p class="wp-block-paragraph"><strong>Development in Visual Studio</strong></p>

<p class="wp-block-paragraph">This is a good point to bring up the ease of development afforded by the IDE. Development for the HMI is integrated directly into Visual Studio, which is very familiar to DMC from our extensive .NET development. The Visual Studio pane and menu system&rsquo;s familiarity makes navigation quick, and Beckhoff&rsquo;s custom screens are also very easy to use. Integrating development into a widely used and well-regarded editor allows engineers to develop a simple web-based HMIs for their PLCs without requiring extensive knowledge of web technologies. However, developers familiar with web technologies (like DMC) still have access to the generated results, allowing us to tailor a solution to the exact needs of our clients.</p>

<p class="wp-block-paragraph"><strong>Easy Extension and Customization</strong></p>

<p class="wp-block-paragraph">As mentioned, Beckhoff&rsquo;s existing framework controls allow for rapid development, especially for simple applications. However, the HMI is also very extensible, allowing for flexible and very custom solutions. DMC took an additional course in designing extensions for custom applications. The extensibility allows for custom Javascript interactive controls, in the case that the provided components don&rsquo;t quite fit the bill. Further, the HMI allows for custom server controls in C#, which allows us to develop connect to any system, use any library, or employ any custom code from our .NET expertise. The flexibility of these extensions, combined with the ease of creating a simple solution, makes us very excited to work on projects with this new HMI.</p>

<p class="wp-block-paragraph">Thanks to Zachary Daulton and co. at Beckhoff for hosting us and giving us a preview of the software!</p>
<p>The post <a href="https://static.dmcinfo.com/blog/22685/dmc-attends-inaugural-twincat-hmi-training/">DMC Attends Inaugural TwinCAT HMI Training</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
