<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mohamed Aiman</title>
    <description>The latest articles on DEV Community by Mohamed Aiman (@darkguyaiman).</description>
    <link>https://dev.to/darkguyaiman</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4165151%2Fa006c79e-48c1-4989-aa29-99638017160a.png</url>
      <title>DEV Community: Mohamed Aiman</title>
      <link>https://dev.to/darkguyaiman</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/darkguyaiman"/>
    <language>en</language>
    <item>
      <title>Building a server-rendered admin UI with Express, EJS, and SEN-JS</title>
      <dc:creator>Mohamed Aiman</dc:creator>
      <pubDate>Tue, 06 Oct 2026 02:09:29 +0000</pubDate>
      <link>https://dev.to/darkguyaiman/building-a-server-rendered-admin-ui-with-express-ejs-and-sen-js-mj0</link>
      <guid>https://dev.to/darkguyaiman/building-a-server-rendered-admin-ui-with-express-ejs-and-sen-js-mj0</guid>
      <description>&lt;p&gt;Admin screens usually need the same building blocks: navigation, tables, search, filters, and forms. In my public project SEN-JS, I organize those pieces as reusable EJS components, with Express handling the page rendering.&lt;/p&gt;

&lt;p&gt;This walkthrough covers the project’s documented component model and how to explore it locally. The source is available at &lt;a href="https://github.com/Darkguyaiman/SEN-JS" rel="noopener noreferrer"&gt;Darkguyaiman/SEN-JS&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Start with the page and its data
&lt;/h2&gt;

&lt;p&gt;A server-rendered page can receive its title, navigation, and rows in one render operation. In SEN-JS, the &lt;code&gt;renderPage&lt;/code&gt; helper connects the page template to the component registry. That keeps a route focused on preparing data while templates describe the interface.&lt;/p&gt;

&lt;p&gt;The repository separates &lt;code&gt;routes/&lt;/code&gt;, &lt;code&gt;views/&lt;/code&gt;, and &lt;code&gt;components/&lt;/code&gt;. Shared rendering behavior lives in &lt;code&gt;lib/core/Component.js&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Keep each component in its own folder
&lt;/h2&gt;

&lt;p&gt;A component has an EJS template and, when it needs browser behavior, an optional JavaScript file. For example:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;components/
  sidebar/
    sidebar.ejs
    sidebar.js
  table/
  search-bar/
  filter/
  calendar/
  button/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This makes the unit of reuse concrete: markup and related behavior live together. The project loads scripts for the components used on the page, so adding a button does not mean manually importing every component script.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Pass explicit props
&lt;/h2&gt;

&lt;p&gt;Here is a small EJS example using the documented button interface:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;%- sen.component('button', {
  label: 'Save',
  variant: 'primary'
}) %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The button API includes props such as &lt;code&gt;label&lt;/code&gt;, &lt;code&gt;variant&lt;/code&gt;, &lt;code&gt;size&lt;/code&gt;, &lt;code&gt;href&lt;/code&gt;, and &lt;code&gt;disabled&lt;/code&gt;. Tables receive &lt;code&gt;columns&lt;/code&gt; and &lt;code&gt;rows&lt;/code&gt;, while filters receive their options and selected value. Explicit inputs help keep page-specific content out of shared templates.&lt;/p&gt;

&lt;p&gt;The table component also supports a &lt;code&gt;cardTitle&lt;/code&gt; property for its mobile card presentation. That is useful when the same records need to be readable on both a wide admin screen and a phone.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Explore it locally
&lt;/h2&gt;

&lt;p&gt;With Node.js and npm available, clone the repository and install its dependencies:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/Darkguyaiman/SEN-JS.git
cd SEN-JS
npm install
npm run build:css
npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The README documents demo data when MySQL is unavailable. To use a database, copy &lt;code&gt;.env.example&lt;/code&gt; to &lt;code&gt;.env&lt;/code&gt;, configure MySQL, and follow the schema setup instructions in the repository. Keep real credentials out of Git.&lt;/p&gt;

&lt;p&gt;The development script watches Tailwind and runs the Express server. For a new component, create &lt;code&gt;components/my-widget/my-widget.ejs&lt;/code&gt;, add &lt;code&gt;my-widget.js&lt;/code&gt; if needed, then use &lt;code&gt;sen.component('my-widget', props)&lt;/code&gt; in a page. Rebuild the CSS after adding template classes.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this approach trades off
&lt;/h2&gt;

&lt;p&gt;I use this structure to keep ordinary admin workflows close to their server-rendered pages. It still needs appropriate authentication, input validation, and database handling for each application. A UI component framework does not provide all of those application rules automatically.&lt;/p&gt;

&lt;p&gt;For a dashboard that mainly displays records and submits forms, reusable templates are a practical starting point. For complex browser state, I would evaluate the interaction requirements separately.&lt;/p&gt;

&lt;p&gt;You can browse &lt;a href="https://github.com/Darkguyaiman/SEN-JS" rel="noopener noreferrer"&gt;SEN-JS on GitHub&lt;/a&gt; or explore my other web development work at &lt;a href="https://darkguyaiman.com/" rel="noopener noreferrer"&gt;darkguyaiman.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article was prepared with AI assistance and checked against the public project documentation.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
    </item>
  </channel>
</rss>
