











{"author":"Faiq Najib Al-Aziz","body":"\nIn [episode two](/en/writing/2026/hijrah-frontend-02/) I mentioned the numbers: one UI library appears in 101 files, the other in just 13. This time I poked around a little more. I found two things that made me pause, then laugh at my screen, hehe.\n\nTurns out the two **never appear in the same file**. And the less-used library has the components people look for most. Odd, right? Here is what I found.\n\n## Two Libraries, One Unwritten Boundary\n\nThe first library is used on more pages. It provides the _paginator_, _button_, _skeleton_, _card_, and even an image _galleria_. Nearly every page uses one of its components; 101 files call it.[^1]\n\nThe second library appears in only 13 files, mostly report pages. But the _DatePicker_, _TimePicker_, and _Select_ are available only there. When a report needs a calendar, those are the components people look for.\n\nI checked the files one by one, and **none use both libraries**. They seem to have a boundary, though I could not find a note explaining when or why it appeared. The pattern still holds across the files I checked.\n\n## A Dictionary in the Reducer's Pocket\n\nThis second finding is my favorite. One library needs a _locale_ so its calendar labels appear in Indonesian. Fair enough. But the import location made me stop for a moment: **inside a _reducer_**.\n\nReducers usually handle data such as numbers and statuses. Here, three different reducers each carry the same dictionary for the presentation layer.\n\nWhy is the _locale_ there? Maybe its labels need to be available when the _state_ is assembled, or maybe it is a leftover from an old copy-paste. I do not know yet. It feels out of place, but it has worked for years. I made a note and left it alone for this port.\n\n## Three Eras of Styling\n\nThere are three generations of _styling_ in the repo:\n\n1. **Classic _global CSS_**: 48 stylesheets that can affect other elements with the same _class_ name.\n2. **UI library defaults**: each library's theme, sometimes bleeding into the other's territory.\n3. **Tailwind**: the new generation with its own _config_, plus a fix document at the repo root that I mentioned in [episode one](/en/writing/2026/hijrah-frontend-01/).\n\nAll three are still in use. Older pages keep their old styling, while others use a UI library or Tailwind. The result is not uniform. That is the _frontend_ we ported, hehe.\n\n## What We Did (and Didn't)\n\nDuring the thin port, we **didn't standardize** any of the above. We didn't migrate libraries, separate reducers from their locale, or remove any styling era.\n\nWe kept one boundary: a file cannot mix the two libraries. We have now written down the rule that used to be an unwritten habit. Large-scale standardization during the move would break [episode four's](/en/writing/2026/hijrah-backend-04/) rule, but in _frontend_ form. That can wait until the port is done.\n\n## My Notes\n\n1. **Two libraries can coexist.** What matters is having a clear boundary between them.\n2. **Start with a simple file-level rule.** We don't need special tooling to keep the two from mixing.\n3. **A locale import in a reducer points to a leaky layer boundary.** For now, it's enough to note it because the code still works.\n4. **Keep the port separate from standardization.** Move first; larger changes can come later.\n\nThe next episode closes the series. I will look at the two sides of the same building, what changed after both the _backend_ and _frontend_ moved, and which inheritances we decided to keep. See you there.\n\nCheers.\n\n[^1]: File counts and the component list were measured directly from the repo as this episode was written; minor components aren't all listed.\n\n[^2]: Code examples and file names are simplified; the structure matches, the contents don't matter for the story.\n","body_clean":"In episode two I mentioned the numbers: one UI library appears in 101 files, the other in just 13. This time I poked around a little more. I found two things that made me pause, then laugh at my screen, hehe.\nTurns out the two never appear in the same file. And the less-used library has the components people look for most. Odd, right? Here is what I found.\nTwo Libraries, One Unwritten Boundary #The first library is used on more pages. It provides the paginator, button, skeleton, card, and even an image galleria. Nearly every page uses one of its components; 101 files call it.1\nThe second library appears in only 13 files, mostly report pages. But the DatePicker, TimePicker, and Select are available only there. When a report needs a calendar, those are the components people look for.\nI checked the files one by one, and none use both libraries. They seem to have a boundary, though I could not find a note explaining when or why it appeared. The pattern still holds across the files I checked.\nA Dictionary in the Reducer\u0026rsquo;s Pocket #This second finding is my favorite. One library needs a locale so its calendar labels appear in Indonesian. Fair enough. But the import location made me stop for a moment: inside a reducer.\nReducers usually handle data such as numbers and statuses. Here, three different reducers each carry the same dictionary for the presentation layer.\nWhy is the locale there? Maybe its labels need to be available when the state is assembled, or maybe it is a leftover from an old copy-paste. I do not know yet. It feels out of place, but it has worked for years. I made a note and left it alone for this port.\nThree Eras of Styling #There are three generations of styling in the repo:\nClassic global CSS: 48 stylesheets that can affect other elements with the same class name. UI library defaults: each library\u0026rsquo;s theme, sometimes bleeding into the other\u0026rsquo;s territory. Tailwind: the new generation with its own config, plus a fix document at the repo root that I mentioned in episode one. All three are still in use. Older pages keep their old styling, while others use a UI library or Tailwind. The result is not uniform. That is the frontend we ported, hehe.\nWhat We Did (and Didn\u0026rsquo;t) #During the thin port, we didn\u0026rsquo;t standardize any of the above. We didn\u0026rsquo;t migrate libraries, separate reducers from their locale, or remove any styling era.\nWe kept one boundary: a file cannot mix the two libraries. We have now written down the rule that used to be an unwritten habit. Large-scale standardization during the move would break episode four\u0026rsquo;s rule, but in frontend form. That can wait until the port is done.\nMy Notes # Two libraries can coexist. What matters is having a clear boundary between them. Start with a simple file-level rule. We don\u0026rsquo;t need special tooling to keep the two from mixing. A locale import in a reducer points to a leaky layer boundary. For now, it\u0026rsquo;s enough to note it because the code still works. Keep the port separate from standardization. Move first; larger changes can come later. The next episode closes the series. I will look at the two sides of the same building, what changed after both the backend and frontend moved, and which inheritances we decided to keep. See you there.\nCheers.\nFile counts and the component list were measured directly from the repo as this episode was written; minor components aren\u0026rsquo;t all listed.\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","canonical":"https://najib.id/en/writing/2026/hijrah-frontend-04/","description":"Episode 4 of the Hijrah Frontend series: primereact and antd coexisting in one application without ever meeting in a single file. About demarcation lines, a UI dictionary in a reducer's pocket, and three styling eras.","language":"en","lastmod":"2026-10-29T09:31:17Z","publishedAt":"2026-09-23T09:00:04Z","readingTime":3,"section":"writing","series":"Hijrah Frontend","tags":["frontend","ui","consistency","story"],"title":"Hijrah Frontend (4): Two UI Libraries, Two Naming Eras","type":"writing","url":"https://najib.id/en/writing/2026/hijrah-frontend-04/","wordCount":595}
