Skip to content

Migrating from UIMenu to HighRise Menu

This guide will help you migrate from the ghl-ui Menu component to the new HighRise Menu component.

WARNING

renderIcon to be added back to the library

Component Implementation Changes

Import Changes

diff
- import { UIMenu } from '@gohighlevel/ghl-ui'
+ import { HLMenu } from '@platform-ui/highrise'

Breaking Changes

The following architectural changes have been made:

  1. Option Structure Changes:

    • More structured option format with specific types
    • Support for custom rendering via render functions
    • New noPadding property for custom spacing control
  2. Props Changes:

    • Removed indent and rootIndent props
    • Added required id prop
    • New defaultExpandedKeys prop for controlling expanded state
    • New activeKey prop for controlling active item
  3. Event Changes:

    • Added update:expanded-key event for expanded state changes

Props Changes

  1. New Required Props:

    • id: Required for accessibility
  2. Changed Props:

    • value -> value (now with stricter type definition)
    • options -> options (enhanced structure)
  3. New Optional Props:

    • defaultExpandedKeys: Control initial expanded state
    • activeKey: Control active menu item
  4. Removed Props:

    • indent: No longer configurable
    • rootIndent: No longer configurable

Examples

Basic Menu

diff
- <UIMenu :options="menuOptions" v-model:value="activeKey" />
+ <HLMenu
+   id="main-menu"
+   :options="menuOptions"
+   v-model:value="activeKey"
+ />

// Script section
- const menuOptions = [
-   {
-     label: 'Home',
-     key: 'home',
-     icon: renderIcon(HomeIcon)
-   }
- ]

+ const menuOptions = [
+   {
+     label: 'Home',
+     key: 'home',
+     icon: () => h(HomeIcon)
+   }
+ ]

With Groups and Icons

diff
- <UIMenu :options="menuOptions" v-model:value="activeKey" />
+ <HLMenu
+   id="grouped-menu"
+   :options="menuOptions"
+   v-model:value="activeKey"
+   :default-expanded-keys="['group-1']"
+ />

// Script section
- const menuOptions = [
-   {
-     type: 'group',
-     label: 'Group 1',
-     children: [
-       {
-         label: 'Item 1',
-         key: 'item-1',
-         icon: renderIcon(UserIcon)
-       }
-     ]
-   }
- ]

+ const menuOptions = [
+   {
+     type: 'group',
+     label: 'Group 1',
+     key: 'group-1',
+     children: [
+       {
+         label: 'Item 1',
+         key: 'item-1',
+         icon: () => h(UserIcon)
+       }
+     ]
+   }
+ ]

Custom Rendered Items

vue
<template>
  <HLMenu id="custom-menu" :options="menuOptions" v-model:value="activeKey" />
</template>

<script setup>
import { HLButton } from '@platform-ui/highrise'
import { PlaceholderIcon } from '@gohighlevel/ghl-icons/24/outline'

const menuOptions = [
  {
    label: () =>
      h(
        HLButton,
        {
          id: 'new-conversation',
          size: '3xs',
          color: 'blue',
          variant: 'tertiary',
          style: {
            width: '100%',
          },
        },
        {
          iconLeft: PlaceholderIcon,
          default: () => 'New Conversation',
        }
      ),
    key: 'button',
    noPadding: true,
  },
]
</script>

With Nested Items and Disabled State

vue
<template>
  <HLMenu id="nested-menu" :options="menuOptions" v-model:value="activeKey" :default-expanded-keys="['parent']" />
</template>

<script setup>
import { BookOpen01Icon, AlertCircleIcon } from '@gohighlevel/ghl-icons/24/outline'

const menuOptions = [
  {
    label: 'Parent Item',
    key: 'parent',
    icon: () => h(BookOpen01Icon),
    children: [
      {
        label: 'Child Item',
        key: 'child',
        icon: () => h(AlertCircleIcon),
        disabled: true,
      },
    ],
  },
]
</script>

Type Definitions

typescript
interface MenuOption {
  label: string | (() => VNode) // Text or custom render function
  key: string | number // Unique identifier
  icon?: () => VNode // Optional icon
  disabled?: boolean // Disable the menu item
  children?: MenuOption[] // Nested menu items
  type?: 'group' | 'divider' // Special item types
  noPadding?: boolean // Control item padding
}

Best Practices

  1. Always provide unique id props for accessibility
  2. Use defaultExpandedKeys for initial expanded state
  3. Leverage custom rendering for complex items
  4. Group related items using the group type
  5. Use consistent icon sizes (24px recommended)
  6. Keep menu items concise and clear
  7. Use appropriate nesting levels
  8. Consider mobile responsiveness
  9. Implement proper event handling
  10. Follow accessibility guidelines

Additional Notes

  1. The component provides built-in responsive behavior
  2. Supports unlimited nesting levels
  3. Automatic indentation handling
  4. Consistent styling with HighRise design system
  5. Built-in accessibility features
  6. Support for RTL layouts
  7. Improved keyboard navigation
  8. Better mobile support
  9. Consistent hover and active states
  10. Integration with other HighRise components