diff --git a/Content.Shared/Trigger/Components/Triggers/TriggerOnMeleeHitComponent.cs b/Content.Shared/Trigger/Components/Triggers/TriggerOnMeleeHitComponent.cs
new file mode 100644
index 0000000000..4277941227
--- /dev/null
+++ b/Content.Shared/Trigger/Components/Triggers/TriggerOnMeleeHitComponent.cs
@@ -0,0 +1,25 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Trigger.Components.Triggers;
+
+///
+/// Triggers when this entity is swung as a melee weapon and hits at least one target.
+///
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+public sealed partial class TriggerOnMeleeHitComponent : BaseTriggerOnXComponent
+{
+ ///
+ /// If true, this trigger will activate individually for each entity hit.
+ /// If false, this trigger will always activate only once.
+ ///
+ [DataField, AutoNetworkedField]
+ public bool TriggerEveryHit;
+
+ ///
+ /// If true, the "user" of the trigger is the entity hit by the melee.
+ /// If false, user is the entity which attacked with the melee weapon.
+ ///
+ /// If TriggerEveryHit is false, the user is randomly chosen from hit entities.
+ [DataField, AutoNetworkedField]
+ public bool TargetIsUser;
+}
diff --git a/Content.Shared/Trigger/Components/Triggers/TriggerOnMeleeMissComponent.cs b/Content.Shared/Trigger/Components/Triggers/TriggerOnMeleeMissComponent.cs
new file mode 100644
index 0000000000..ea175fa091
--- /dev/null
+++ b/Content.Shared/Trigger/Components/Triggers/TriggerOnMeleeMissComponent.cs
@@ -0,0 +1,10 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Trigger.Components.Triggers;
+
+///
+/// Triggers when this entity is swung as a melee weapon and hits nothing.
+/// The user is the entity swinging the weapon.
+///
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+public sealed partial class TriggerOnMeleeMissComponent : BaseTriggerOnXComponent;
diff --git a/Content.Shared/Trigger/Components/Triggers/TriggerOnMeleeSwingComponent.cs b/Content.Shared/Trigger/Components/Triggers/TriggerOnMeleeSwingComponent.cs
new file mode 100644
index 0000000000..b035c20b10
--- /dev/null
+++ b/Content.Shared/Trigger/Components/Triggers/TriggerOnMeleeSwingComponent.cs
@@ -0,0 +1,18 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Trigger.Components.Triggers;
+
+///
+/// Triggers when this entity is swung as a melee weapon, regardless of whether it hits something.
+///
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+public sealed partial class TriggerOnMeleeSwingComponent : BaseTriggerOnXComponent
+{
+ ///
+ /// If true, the "user" of the trigger is the entity hit by the melee. User is null if nothing is hit.
+ /// If false, user is the entity which attacked with the melee weapon.
+ ///
+ /// If true and multiple targets are hit, the user is randomly chosen from hit entities.
+ [DataField, AutoNetworkedField]
+ public bool TargetIsUser;
+}
diff --git a/Content.Shared/Trigger/Systems/MeleeTriggerSystem.cs b/Content.Shared/Trigger/Systems/MeleeTriggerSystem.cs
new file mode 100644
index 0000000000..b7433a2987
--- /dev/null
+++ b/Content.Shared/Trigger/Systems/MeleeTriggerSystem.cs
@@ -0,0 +1,58 @@
+using Content.Shared.Trigger.Components.Triggers;
+using Content.Shared.Weapons.Melee.Events;
+
+namespace Content.Shared.Trigger.Systems;
+
+///
+/// Trigger system for melee related triggers.
+///
+public sealed class MeleeTriggerSystem : EntitySystem
+{
+ [Dependency] private readonly TriggerSystem _trigger = default!;
+
+ ///
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnMissTrigger);
+ SubscribeLocalEvent(OnSwingTrigger);
+ SubscribeLocalEvent(OnHitTrigger);
+ }
+
+ private void OnMissTrigger(Entity ent, ref MeleeHitEvent args)
+ {
+ if (args.HitEntities.Count == 0)
+ _trigger.Trigger(ent.Owner, args.User, ent.Comp.KeyOut);
+ }
+
+ private void OnSwingTrigger(Entity ent, ref MeleeHitEvent args)
+ {
+ EntityUid? target;
+ if (args.HitEntities.Count == 0)
+ target = ent.Comp.TargetIsUser ? null : args.User;
+ else
+ target = ent.Comp.TargetIsUser ? args.HitEntities[0] : args.User;
+
+ _trigger.Trigger(ent.Owner, target, ent.Comp.KeyOut);
+ }
+
+ private void OnHitTrigger(Entity ent, ref MeleeHitEvent args)
+ {
+ if (args.HitEntities.Count == 0)
+ return;
+
+ if (!ent.Comp.TriggerEveryHit)
+ {
+ var target = ent.Comp.TargetIsUser ? args.HitEntities[0] : args.User;
+ _trigger.Trigger(ent.Owner, target, ent.Comp.KeyOut);
+ return;
+ }
+
+ // if TriggerEveryHit
+ foreach (var target in args.HitEntities)
+ {
+ _trigger.Trigger(ent.Owner, ent.Comp.TargetIsUser ? target : args.User, ent.Comp.KeyOut);
+ }
+ }
+}