diff --git a/flag.inc b/flag.inc
index ca27db4..7d5d7bf 100644
--- a/flag.inc
+++ b/flag.inc
@@ -1248,6 +1248,7 @@
       'show_on_page' => TRUE,
       'show_on_teaser' => TRUE,
       'show_on_form' => FALSE,
+      'show_contextual_link' => FALSE,
       'access_author' => '',
       'i18n' => 0,
     );
@@ -1301,6 +1302,12 @@
       '#description' => t('If you elect to have a checkbox on the node edit form, you may specify its initial state in the settings form <a href="@content-types-url">for each content type</a>.', array('@content-types-url' => url('admin/structure/types'))),
       '#access' => empty($this->locked['show_on_form']),
     );
+    $form['display']['show_contextual_link'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Display in contextual links'),
+      '#default_value' => $this->show_contextual_link,
+      '#access' => empty($this->locked['show_contextual_link']) && module_exists('contextual'),
+    );
   }
 
   function _load_content($content_id) {
diff --git a/flag.module b/flag.module
index 957bb12..fb898b3 100644
--- a/flag.module
+++ b/flag.module
@@ -446,6 +446,39 @@
   }
 }
 
+/*
+ * Implements hook_contextual_links_view_alter().
+ */
+function flag_contextual_links_view_alter(&$element, $items) {
+
+  // Check if we have a node link to process
+  if (isset($element['#element']['#node']->nid)) {
+    $node = $element['#element']['#node'];
+
+    // Get all possible flags for this content-type.
+    $flags = flag_get_flags('node');
+
+    foreach ($flags as $name => $flag) {
+      if (!$flag->show_contextual_link) {
+        continue;
+      }
+
+      $content_id = $flag->get_content_id($node);
+      if (!$flag->access($content_id) && (!$flag->is_flagged($content_id) || !$flag->access($content_id, 'flag'))) {
+        // User has no permission to use this flag or flag does not apply to this
+        // content. The link is not skipped if the user has "flag" access but
+        // not "unflag" access (this way the unflag denied message is shown).
+        continue;
+      }
+
+      $element['#links']['flag-'. $name] = array(
+        'title' => $flag->theme($flag->is_flagged($content_id) ? 'unflag' : 'flag', $content_id),
+        'html' => TRUE,
+      );
+    }
+  }
+}
+
 /**
  * Implements hook_comment_view().
  */
diff --git a/theme/flag.css b/theme/flag.css
index d069869..610b4b0 100644
--- a/theme/flag.css
+++ b/theme/flag.css
@@ -13,6 +13,15 @@
   position: relative;
 }
 
+/* Better contextual link support, prevent line wrapping. */
+ul.contextual-links li .flag-wrapper a {
+  display: inline-block;
+}
+
+ul.contextual-links li .flag-wrapper {
+  display: block;
+}
+
 /* The rest deals with indicating the waiting state. */
 
 .flag-waiting a {