# Emojis in Custom Section

**URL:** https://meta.discourse.org/t/emojis-in-custom-section/378390
**Category:** UX
**Tags:** sidebar, ux
**Created:** [August 13, 2025, 6:40am UTC](https://meta.discourse.org/t/emojis-in-custom-section/378390 "2025-08-13T06:40:20Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![alltiagocom](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/alltiagocom/32/492709_2.png) [@alltiagocom](https://meta.discourse.org/u/alltiagocom)
#### Post date: [August 13, 2025, 6:40am UTC](https://meta.discourse.org/t/emojis-in-custom-section/378390/1 "2025-08-13T06:40:20Z")

</div>

I’m using Emojis in the Categories section in the sidebar, but I also have a custom section that is public. I wanted to have the same colorful icons in that section so it doesn’t get so “bland” compared to the Categories section.

 ![image](https://global.discourse-cdn.com/meta/original/4X/c/9/e/c9edd4048b716a28a5d18dfcf9a3264ab7437d98.png)

 ![image](https://global.discourse-cdn.com/meta/original/4X/9/3/1/931aedcce142ae7a931de0e4102bf80d329f2ab8.png)

Is this possible?

---

<div class="post-metadata">

### Author: ![alltiagocom](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/alltiagocom/32/492709_2.png) [@alltiagocom](https://meta.discourse.org/u/alltiagocom)
#### Post date: [August 13, 2025, 7:50am UTC](https://meta.discourse.org/t/emojis-in-custom-section/378390/2 "2025-08-13T07:50:23Z")

</div>

With the help of both ChatGPT and Claude, I was able to make it work and very customizable:

 ![image](https://global.discourse-cdn.com/meta/original/4X/7/f/e/7fe09283d0adf4c84c942d696eea2a75d8a7c528.png)

If you want to do it, create a new component and add this to the CSS tab:

```css
.sidebar-section-link-prefix .emoji.prefix-emoji {
  width: 1rem !important;
  height: 1rem !important;
}

```

> For my particular case `1rem` works great. Adjust to your forum/community

Then in the JS tab:

```js
import { apiInitializer } from "discourse/lib/api";
import { emojiUrlFor } from "discourse/lib/text";

export default apiInitializer("0.11.1", (api) => {
  // Map section names to IDs
  const sectionIds = {
    "community": 1,
    "tiago": 2,
    "personal-section": 3,
    // Add more sections here
  };
  
  // Map of [sectionId, itemName] to emoji names
  const iconReplacements = {
    // Community section (ID: 1)
    "1,admin": "wrench",
    "1,review": "triangular_flag_on_post",
    "1,everything": "books",
    "1,my-posts": "writing_hand",
    "1,my-messages": "envelope_with_arrow",
    
    // Tiago section (ID: 2)
    "2,Journal": "notebook_with_decorative_cover",
    "2,Music": "musical_note",
    "2,About": "bust_in_silhouette",
    
    // Personal section (ID: 3)
    "3,Backups": "floppy_disk",
    "3,Scheduled": "clock3",
    "3,Staff": "lock",
    "3,Components": "electric_plug",
  };

  function replaceIcons() {
    Object.entries(sectionIds).forEach(([sectionName, sectionId]) => {
      Object.entries(iconReplacements).forEach(([key, emojiName]) => {
        const [keyId, itemName] = key.split(',');
        
        // Only process if this replacement is for the current section
        if (parseInt(keyId) === sectionId) {
          const url = emojiUrlFor(emojiName);
          
          // Try multiple selectors to catch both hamburger menu and fixed sidebar
          const selectors = [
            // Fixed sidebar selector
            `div[data-section-name="${sectionName}"] li[data-list-item-name="${itemName}"] .sidebar-section-link-prefix.icon`,
            // Hamburger menu selector (more specific)
            `.menu-panel div[data-section-name="${sectionName}"] li[data-list-item-name="${itemName}"] .sidebar-section-link-prefix.icon`,
            // Generic fallback
            `[data-section-name="${sectionName}"] [data-list-item-name="${itemName}"] .sidebar-section-link-prefix.icon`
          ];
          
          for (const selector of selectors) {
            const prefix = document.querySelector(selector);
            
            if (prefix && url) {
              // Check if it's already replaced to avoid unnecessary DOM manipulation
              if (!prefix.querySelector('.prefix-emoji')) {
                prefix.innerHTML = `
                  <img src="${url}"
                       title="${emojiName}"
                       alt="${emojiName}"
                       class="emoji prefix-emoji">
                `;
              }
              break; // Exit loop once we find and replace the icon
            }
          }
        }
      });
    });
  }

  // Run on page change
  api.onPageChange(replaceIcons);
  
  // Also run with delay to catch dynamically loaded content
  api.onPageChange(() => {
    setTimeout(replaceIcons, 100);
    setTimeout(replaceIcons, 500);
  });

  // Enhanced MutationObserver to catch sidebar changes
  const observer = new MutationObserver((mutations) => {
    let shouldReplace = false;
    
    mutations.forEach((mutation) => {
      // Watch for added nodes (original functionality)
      mutation.addedNodes.forEach((node) => {
        if (node.nodeType === Node.ELEMENT_NODE) {
          if (node.classList?.contains('menu-panel') || 
              node.querySelector?.('.sidebar-sections') ||
              node.classList?.contains('sidebar-sections') ||
              node.querySelector?.('[data-section-name]')) {
            shouldReplace = true;
          }
        }
      });
      
      // Watch for attribute changes on sidebar sections (collapse/expand)
      if (mutation.type === 'attributes' && mutation.target.nodeType === Node.ELEMENT_NODE) {
        const target = mutation.target;
        if (target.matches('[data-section-name]') || 
            target.closest('[data-section-name]') ||
            target.matches('.sidebar-section') ||
            target.closest('.sidebar-section')) {
          shouldReplace = true;
        }
      }
      
      // Watch for childList changes in sidebar sections
      if (mutation.type === 'childList' && mutation.target.nodeType === Node.ELEMENT_NODE) {
        const target = mutation.target;
        if (target.matches('[data-section-name]') || 
            target.closest('[data-section-name]') ||
            target.querySelector('[data-section-name]')) {
          shouldReplace = true;
        }
      }
    });
    
    if (shouldReplace) {
      setTimeout(replaceIcons, 50);
    }
  });

  // Start observing with enhanced options
  observer.observe(document.body, {
    childList: true,
    subtree: true,
    attributes: true, // Watch for attribute changes
    attributeFilter: ['class', 'style', 'aria-expanded'], // Common attributes that change on collapse/expand
  });

  // Additional event listeners for common sidebar interactions
  document.addEventListener('click', (event) => {
    // Check if click was on a sidebar section header or toggle button
    if (event.target.closest('.sidebar-section-header') ||
        event.target.closest('[data-section-name]') ||
        event.target.matches('.sidebar-section-toggle')) {
      setTimeout(replaceIcons, 100);
    }
  });
});

```

I made it so I can easily add new custom sections by name, attributing it an `id` and then creating each section’s mapping.

The reason for that is because I may have 2 sections with the title `Journal`, for example, but maybe I want 2 different emojis for each.

I’m pretty sure there will be someone saying that there’s a component or plugin for this 😉 but it was still fun to go back and forth with ChatGPT and Claude until everything worked the way I wanted.

Hope this helps other users.

> If you see anything that can be tweaked/improved, please share 🙌

---

<div class="post-metadata">

### Author: ![alltiagocom](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/alltiagocom/32/492709_2.png) [@alltiagocom](https://meta.discourse.org/u/alltiagocom)
#### Post date: [August 15, 2025, 8:16am UTC](https://meta.discourse.org/t/emojis-in-custom-section/378390/4 "2025-08-15T08:16:10Z")

</div>

I just updated the JS code, because I noticed that on mobile it was still showing the default icons. Everything is working as expected on both mobile and desktop.

---

<div class="post-metadata">

### Author: ![alltiagocom](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/alltiagocom/32/492709_2.png) [@alltiagocom](https://meta.discourse.org/u/alltiagocom)
#### Post date: [August 16, 2025, 9:51pm UTC](https://meta.discourse.org/t/emojis-in-custom-section/378390/5 "2025-08-16T21:51:46Z")

</div>

Another edit: when I would collapse and expand the section, the emojis would be gone and replaced with the original icons. It’s working now and I updated the JS code again.

---

<div class="post-metadata">

### Author: ![mcwumbly](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/mcwumbly/32/103861_2.png) [@mcwumbly](https://meta.discourse.org/u/mcwumbly)
#### Post date: [August 17, 2025, 1:05pm UTC](https://meta.discourse.org/t/emojis-in-custom-section/378390/7 "2025-08-17T13:05:47Z")

</div>

Glad you found a way to do this – I think this would be a pretty natural fit for a core feature, now that we support emoji for categories.

---

<div class="post-metadata">

### Author: ![alltiagocom](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/alltiagocom/32/492709_2.png) [@alltiagocom](https://meta.discourse.org/u/alltiagocom)
#### Post date: [August 17, 2025, 3:04pm UTC](https://meta.discourse.org/t/emojis-in-custom-section/378390/8 "2025-08-17T15:04:43Z")

</div>

I agree. Hope this becomes a native feature eventually. Until that happens, this custom component is doing its job 🙂

---

<div class="post-metadata">

### Author: ![system](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/system/32/443519_2.png) [@system](https://meta.discourse.org/u/system)
#### Post date: [September 17, 2025, 9:15am UTC](https://meta.discourse.org/t/emojis-in-custom-section/378390/10 "2025-09-17T09:15:41Z")

</div>

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.
