Lädt...

🔧 ButtonDropDown vuejs and Primevue


Nachrichtenbereich: 🔧 Programmierung
🔗 Quelle: dev.to

ActionDropdown Component

The ActionDropdown is a reusable Vue.js component built using PrimeVue's Button and Menu components. It provides a dropdown menu for actions, allowing developers to define customizable menu items with labels, icons, commands, and separators.

Features

  • Customizable Button: Configure label, icon, severity (e.g., primary, secondary), size, and more.
  • Dynamic Menu Items: Define menu actions with labels, icons, commands, and styling.
  • Event Emission: Emits an action event when a menu item is clicked.
  • Flexible Alignment: Align the dropdown menu to the left or right.
  • Accessibility: Supports disabling the button or individual menu items.
  • Styling Support: Tailwind CSS and scoped styles for customization.

Example Usage

Here’s how you can use the ActionDropdown component in your Vue application:

<template>
  <div>
    <ActionDropdown
      :actions="getRowActions"
      button-label="Actions"
      button-icon="pi pi-ellipsis-v"
      button-severity="secondary"
      size="small"
      text-only
      @action="handleAction"
    />
  </div>
</template>

<script setup>
import { ref } from "vue";
import ActionDropdown from "@/components/buttons/ActionDropdown.vue";

const getRowActions = [
  {
    label: "View Details",
    icon: "pi pi-eye",
    command: () => viewDetails(),
  },
  {
    label: "Edit",
    icon: "pi pi-pencil",
    command: () => editItem(),
  },
  { separator: true },
  {
    label: "Delete",
    icon: "pi pi-trash",
    command: () => confirmDelete(),
    class: "danger-item",
  },
];

const handleAction = (action) => {
  console.log("Action performed:", action.label);
};

const viewDetails = () => {
  console.log("Viewing details...");
};

const editItem = () => {
  console.log("Editing item...");
};

const confirmDelete = () => {
  console.log("Confirming delete...");
};
</script>

Props

Prop Type Default Description
actions Array [] List of menu actions. Each action can have label, icon, command, class, and separator.
buttonLabel String "Actions" Label text for the button.
buttonIcon String "pi pi-ellipsis-v" Icon class for the button.
buttonSeverity String "secondary" Button severity: primary, secondary, success, info, warning, danger, help.
size String "medium" Button size: small, medium, large.
textOnly Boolean false If true, the button will be styled as a text button.
disabled Boolean false Disables the button.
menuClass String "" Additional CSS classes for the dropdown menu.
appendTo String "body" Determines where to append the dropdown menu.
menuAlignment String "left" Menu alignment: left or right.

Events

Event Payload Description
action Object Fired when a menu item is clicked. Payload contains the action's properties.

Styling

The ActionDropdown component uses Tailwind CSS for styling. Below are some key customizations:

Button Styling

  • .p-button-sm: Small size
  • .p-button-lg: Large size
  • .p-button-text: Text-only button

Menu Styling

  • .p-menuitem: Default menu item styling.
  • .danger-item: Styling for actions that are marked as "danger" (e.g., delete).

Alignment

  • .menu-right: Aligns the dropdown to the right.

Size Variants

  • .small: Small menu items.
  • .large: Large menu items.

Notes

  1. Dependencies:

    • This component relies on PrimeVue's Button and Menu components. Make sure to install and configure PrimeVue in your project.
  2. Tailwind CSS:

    • The styles use Tailwind CSS utilities. Ensure Tailwind CSS is configured in your project.
  3. Validation:

    • Action items are validated to ensure each item has a valid configuration (e.g., label and command are required unless it's a separator).

Installation

To use the ActionDropdown component, copy the file to your project and import it as needed.

Install PrimeVue and Tailwind CSS if not already installed:

npm install primevue @tailwindcss/postcss7-compat

Configure PrimeVue in your main file:

import { createApp } from "vue";
import PrimeVue from "primevue/config";

import App from "./App.vue";
import "./tailwind.css"; // Include Tailwind CSS

const app = createApp(App);
app.use(PrimeVue);
app.mount("#app");
<template>
    <div class="action-dropdown-container">
        <Button
            :label="buttonLabel"
            :icon="buttonIcon"
            :severity="buttonSeverity"
            :class="['action-button', sizeClass, { 'p-button-text': textOnly }]"
            @click="toggleDropdown"
            :disabled="disabled"
        />
        <Menu
            ref="menu"
            :model="menuItems"
            :popup="true"
            :class="menuClass"
            :appendTo="appendTo"
        />
    </div>
</template>

<script setup>
import { ref, computed } from "vue";
import Button from "primevue/button";
import Menu from "primevue/menu";

const props = defineProps({
    // Action items configuration
    actions: {
        type: Array,
        default: () => [],
        validator: (items) => {
            return items.every((item) => {
                // Either has command/to/url, or is a separator
                return (
                    item.separator ||
                    (item.label && (item.command || item.to || item.url))
                );
            });
        },
    },

    // Button appearance
    buttonLabel: {
        type: String,
        default: "Actions",
    },
    buttonIcon: {
        type: String,
        default: "pi pi-ellipsis-v",
    },
    buttonSeverity: {
        type: String,
        default: "secondary",
        validator: (value) =>
            [
                "primary",
                "secondary",
                "success",
                "info",
                "warning",
                "danger",
                "help",
            ].includes(value),
    },
    textOnly: {
        type: Boolean,
        default: false,
    },
    disabled: {
        type: Boolean,
        default: false,
    },

    // Size and layout
    size: {
        type: String,
        default: "medium",
        validator: (value) => ["small", "medium", "large"].includes(value),
    },
    fullWidth: {
        type: Boolean,
        default: false,
    },

    // Menu configuration
    menuClass: {
        type: String,
        default: "",
    },
    appendTo: {
        type: String,
        default: "body",
    },
    menuAlignment: {
        type: String,
        default: "left",
        validator: (value) => ["left", "right"].includes(value),
    },
});

const emit = defineEmits(["action"]);

const menu = ref(null);

// Create stable menu items without reactive dependencies
const menuItems = computed(() => {
    return props.actions.map((action) => {
        if (action.separator) {
            return { separator: true };
        }

        return {
            label: action.label,
            icon: action.icon,
            class: action.class,
            disabled: action.disabled,
            command: () => {
                emit("action", action);
                if (action.command) {
                    action.command();
                }
            },
        };
    });
});

const sizeClass = computed(() => {
    return {
        small: "p-button-sm",
        medium: "",
        large: "p-button-lg",
    }[props.size];
});

const toggleDropdown = (event) => {
    if (props.disabled) return;
    menu.value.toggle(event);
};
</script>

<style scoped>
.action-dropdown-container {
    @apply relative inline-flex;
}

.action-button {
    @apply flex items-center justify-center gap-2;

    &.p-button-text {
        @apply shadow-none;
    }
}

/* Full width variant */
.full-width {
    @apply w-full;

    .action-button {
        @apply w-full;
    }
}
</style>

<style>
/* Menu styling - using global style to override PrimeVue defaults */
.action-dropdown-container .p-menu {
    @apply min-w-[10rem] shadow-lg rounded-md border border-gray-200 mt-1 z-50;

    .p-menuitem {
        @apply hover:bg-gray-50;

        &.p-disabled {
            @apply opacity-50 cursor-not-allowed;
        }
    }

    .p-menuitem-link {
        @apply px-4 py-2 text-sm text-gray-700 hover:text-gray-900 hover:bg-gray-50;

        .p-menuitem-icon {
            @apply text-gray-500 mr-2;
        }

        .p-menuitem-text {
            @apply flex-grow;
        }
    }

    .p-menu-separator {
        @apply border-t border-gray-200 my-1;
    }

    /* Danger items styling */
    .danger-item {
        @apply text-red-600 hover:bg-red-50;

        .p-menuitem-icon {
            @apply text-red-500;
        }
    }
}

/* Right-aligned menu */
.menu-right .p-menu {
    @apply right-0 left-auto;
}

/* Size variants */
.action-dropdown-container.small .p-menu {
    .p-menuitem-link {
        @apply px-3 py-1.5 text-xs;
    }
}

.action-dropdown-container.large .p-menu {
    .p-menuitem-link {
        @apply px-5 py-3 text-base;
    }
}
</style>

...

🔧 ButtonDropDown vuejs and Primevue


📈 92.75 Punkte
🔧 Programmierung

🔧 VueJS Intermediate Workshop (Learn VueJS Best Practices)


📈 40.41 Punkte
🔧 Programmierung

🔧 State of VueJS 2018 by the Creator of VueJS


📈 40.41 Punkte
🔧 Programmierung

🔧 VueJs for Beginner 2024 #VueJs Part 3 : Data Binding


📈 40.41 Punkte
🔧 Programmierung

🔧 I created a Japanese Learning Web Application with Nuxt and PrimeVue


📈 32.76 Punkte
🔧 Programmierung

🔧 Build your own Vue UI library with Unstyled PrimeVue Core and Tailwind CSS


📈 32.76 Punkte
🔧 Programmierung

🔧 How to Fix Scroll Restoration Issues with PrimeVue TabView?


📈 31.46 Punkte
🔧 Programmierung

🔧 Wrapping PrimeVue Components: Tips for a Better Developer Experience


📈 31.46 Punkte
🔧 Programmierung

🔧 Deploying a NestJS and VueJS App with Dokploy


📈 21.5 Punkte
🔧 Programmierung

🔧 Main differences between ReactJS and VueJS, in my opinion


📈 21.5 Punkte
🔧 Programmierung

🔧 A simple webpack setup with Bootstrap and VueJS


📈 21.5 Punkte
🔧 Programmierung

🔧 Vuejs and Nuxt challenges where to practice what you have learned?


📈 21.5 Punkte
🔧 Programmierung

🔧 Building a Simple TodoApp with ReactJs Angular and VueJs


📈 21.5 Punkte
🔧 Programmierung

🔧 VueJS part 14: Scoped slots and conditional slot rendering


📈 21.5 Punkte
🔧 Programmierung

🔧 VueJS part 14: Scoped slots and conditional slot rendering


📈 21.5 Punkte
🔧 Programmierung

🔧 VueJS part 12: Exposing methods and data in components


📈 21.5 Punkte
🔧 Programmierung

🔧 Build an Event Calendar App Using NodeJS, VueJS, and SQL Server (Step by Step Tutorial)


📈 21.5 Punkte
🔧 Programmierung

🔧 Getting Started with VueJS and WordPress


📈 21.5 Punkte
🔧 Programmierung

🔧 Serverless Functions and VueJS


📈 21.5 Punkte
🔧 Programmierung

🔧 Vue.js for Beginners 2024 #VueJs Part 6 : State Management with Vuex


📈 20.2 Punkte
🔧 Programmierung

🔧 Vuejs Car Game


📈 20.2 Punkte
🔧 Programmierung

🔧 VueJS: o que é, como funciona e como começar a usar o framework


📈 20.2 Punkte
🔧 Programmierung

🔧 Vue.js for Beginners 2024 #VueJs Part 5 : A Complete Guide to Routing with Vue Router


📈 20.2 Punkte
🔧 Programmierung

🔧 VueJS - JavaScript Framework


📈 20.2 Punkte
🔧 Programmierung

🔧 Vuejs Modern Portfolio


📈 20.2 Punkte
🔧 Programmierung

🔧 How to use SuperTokens in a VueJS app with your own UI


📈 20.2 Punkte
🔧 Programmierung

🔧 Integrating Cloudflare Turnstile into a vuejs application


📈 20.2 Punkte
🔧 Programmierung

🔧 VueJS + Tailwind + DaisyUI = 😎🌷


📈 20.2 Punkte
🔧 Programmierung

🔧 Vue.js for Beginners 2024 #VueJs Part 4 : Form &amp; Event Listener


📈 20.2 Punkte
🔧 Programmierung

🔧 How to integrate hCaptcha into a vuejs application


📈 20.2 Punkte
🔧 Programmierung

🔧 VueJS or ReactJS


📈 20.2 Punkte
🔧 Programmierung

🔧 Is VueJs Still Worth It for Beginners in 2024? #VueJs3 Part 1:Installation


📈 20.2 Punkte
🔧 Programmierung

🔧 What path should i follow, currently i have in my stack Laravel, Wordpress, Vuejs, MySQL


📈 20.2 Punkte
🔧 Programmierung

🔧 Start to use VueJS


📈 20.2 Punkte
🔧 Programmierung

🔧 Spring Boot with VueJS with Spring Security


📈 20.2 Punkte
🔧 Programmierung