diff --git a/css/flag-link-ajax.css b/css/flag-link-ajax.css
new file mode 100644
index 0000000..b70a1ef
--- /dev/null
+++ b/css/flag-link-ajax.css
@@ -0,0 +1,10 @@
+/**
+ * @file
+ * AJAX specific styles for flag links.
+ *
+ * @see flag.html.twig.
+ */
+.js-flag-message {
+  display: inline;
+  margin-left: 1.2em;
+}
diff --git a/flag.libraries.yml b/flag.libraries.yml
index e4322a6..ca63e6d 100644
--- a/flag.libraries.yml
+++ b/flag.libraries.yml
@@ -8,8 +8,22 @@ flag.admin:
     - core/drupalSettings
     - core/drupal.form
 
+# Normal action link library.
 flag.link:
   version: VERSION
   css:
     theme:
       css/flag-link.css: {}
+
+# Ajax action link library.
+flag.link_ajax:
+  version: VERSION
+  js:
+    js/flag-action_link_flash.js: {}
+  css:
+    theme:
+      css/flag-link-ajax.css: {}
+  dependencies:
+    - core/jquery
+    - core/drupal
+    - core/drupal.ajax
diff --git a/js/flag-action_link_flash.js b/js/flag-action_link_flash.js
new file mode 100644
index 0000000..6c10c4f
--- /dev/null
+++ b/js/flag-action_link_flash.js
@@ -0,0 +1,56 @@
+/**
+ * @file
+ * Defines the client side code for the ActionLinkFlashCommand.
+ *
+ * see \Drupal\flag\Ajax\ActionLinkFlashCommand
+ */
+
+(function ($, Drupal) {
+
+  'use strict';
+
+  Drupal.behaviors.flagAttach = {
+    attach: function (context, settings) {
+      // Bind a click handler onto all action links so styles can be applied
+      // while the XHR is in flight.
+      $(context).find('.flag a').each(function (i, element) {
+        $(this).on('click', function () {
+          $(this).parents().first().addClass('flag-waiting');
+        });
+      });
+    }
+  };
+
+  /**
+   * Display message on the screen for a short period of time.
+   *
+   * @param {Drupal.Ajax} [ajax]
+   *   The ajax object.
+   * @param {object} response
+   *   Object holding the server response.
+   * @param {string} response.selector
+   *   The selector of link to be updated.
+   * @param {string} response.message
+   *   The message to be displayed.
+   * @param {number} [status]
+   *   The HTTP status code.
+   */
+  Drupal.AjaxCommands.prototype.actionLinkFlash = function (ajax, response, status) {
+    if (status === 'success') {
+      // Construct a <p> element with escaped message.
+      var p_elem = $('<p class="js-flag-message">').text(response.message);
+
+      $(response.selector).append(p_elem);
+
+      p_elem.fadeIn('fast', function () {
+        $(this).fadeOut(3000, function () {
+          $(this).remove();
+        });
+      });
+    } else {
+      // If the XHR failed, assume the replace command that would normally make
+      // the styling disapear has also failed and remove the temporary styling.
+      $('flag-waiting').toggleClass('flag-waiting');
+    };
+  };
+})(jQuery, Drupal);
diff --git a/src/Ajax/ActionLinkFlashCommand.php b/src/Ajax/ActionLinkFlashCommand.php
new file mode 100644
index 0000000..7498475
--- /dev/null
+++ b/src/Ajax/ActionLinkFlashCommand.php
@@ -0,0 +1,54 @@
+<?php
+
+namespace Drupal\flag\Ajax;
+
+use Drupal\Core\Ajax\CommandInterface;
+
+/**
+ * Flash a message as an action link is updated.
+ *
+ * The client side code can be found in js/flag-action_link_flash.js.
+ *
+ * @ingroup flag
+ */
+class ActionLinkFlashCommand implements CommandInterface {
+
+  /**
+   * Identifies the action link to be flashed.
+   *
+   * @var string
+   */
+  protected $selector;
+
+  /**
+   * The message to be flashed under the link.
+   *
+   * @var string
+   */
+  protected $message;
+
+  /**
+   * Construct a message Flasher.
+   *
+   * @param string $selector
+   *   Identifies the action link to be flashed.
+   * @param string $message
+   *   The message to be displayed.
+   */
+  public function __construct($selector, $message) {
+    $this->selector = $selector;
+    $this->message = $message;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function render() {
+    return [
+      'command' => 'actionLinkFlash',
+      'selector' => $this->selector,
+      'message' => $this->message,
+    ];
+  }
+
+}
diff --git a/src/Controller/ActionLinkController.php b/src/Controller/ActionLinkController.php
index bcb5e75..ce7dd84 100644
--- a/src/Controller/ActionLinkController.php
+++ b/src/Controller/ActionLinkController.php
@@ -5,20 +5,28 @@ namespace Drupal\flag\Controller;
 use Drupal\Core\Ajax\AjaxResponse;
 use Drupal\Core\Ajax\ReplaceCommand;
 use Drupal\Core\Controller\ControllerBase;
-use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\EventSubscriber\MainContentViewSubscriber;
+use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
 use Drupal\Core\Render\RendererInterface;
-use Symfony\Component\DependencyInjection\ContainerInterface;
+use Drupal\flag\Ajax\ActionLinkFlashCommand;
 use Drupal\flag\FlagInterface;
 use Drupal\flag\FlagServiceInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\HttpFoundation\RedirectResponse;
 use Symfony\Component\HttpFoundation\Request;
 
 /**
- * Provides a controller to flag and unflag when routed from a normal link.
+ * Controller responses to flag and unflag action links.
+ *
+ * If the action_link is a normal link then after an update the response to a
+ *  valid request is a redirect to the entity with drupal update message.
+ *
+ * For an ajax_action_link the response is a set of AJAX commands to update the
+ * link in the page. If the user agent has javascript disabled then the
+ * behaviour reverts to that of a normal link.
  */
 class ActionLinkController extends ControllerBase implements ContainerInjectionInterface {
-
   /**
    * The flag service.
    *
@@ -64,8 +72,8 @@ class ActionLinkController extends ControllerBase implements ContainerInjectionI
    * @param \Symfony\Component\HttpFoundation\Request $request
    *   The request.
    *
-   * @return \Symfony\Component\HttpFoundation\RedirectResponse
-   *   The response object.
+   * @return \Drupal\Core\Ajax\AjaxResponse|\Symfony\Component\HttpFoundation\RedirectResponse|null
+   *   The response object, only if successful.
    *
    * @see \Drupal\flag\Plugin\Reload
    */
@@ -81,11 +89,11 @@ class ActionLinkController extends ControllerBase implements ContainerInjectionI
       // link for the existing state of the flag.
     }
 
-    return $this->generateResponse($flag, $entity, $request);
+    return $this->generateResponse($flag, $entity, $request, $flag->getMessage('flag'));
   }
 
   /**
-   * Performs a flagging when called via a route.
+   * Performs a unflagging when called via a route.
    *
    * @param \Drupal\flag\FlagInterface $flag
    *   The flag entity.
@@ -94,8 +102,8 @@ class ActionLinkController extends ControllerBase implements ContainerInjectionI
    * @param \Symfony\Component\HttpFoundation\Request $request
    *   The request.
    *
-   * @return \Symfony\Component\HttpFoundation\RedirectResponse
-   *   The response object.
+   * @return \Drupal\Core\Ajax\AjaxResponse|\Symfony\Component\HttpFoundation\RedirectResponse|null
+   *   The response object, only if successful.
    *
    * @see \Drupal\flag\Plugin\Reload
    */
@@ -111,26 +119,23 @@ class ActionLinkController extends ControllerBase implements ContainerInjectionI
       // link for the existing state of the flag.
     }
 
-    return $this->generateResponse($flag, $entity, $request);
+    return $this->generateResponse($flag, $entity, $request, $flag->getMessage('unflag'));
   }
 
   /**
-   * Generates a response object after handing the un/flag request.
-   *
-   * Depending on the wrapper format of the request, it will either redirect
-   * or return an ajax response.
+   * Generates a response after the flag has been updated.
    *
    * @param \Drupal\flag\FlagInterface $flag
    *   The flag entity.
    * @param \Drupal\Core\Entity\EntityInterface $entity
    *   The entity object.
-   * @param \Symfony\Component\HttpFoundation\Request $request
-   *   The request.
+   * @param string $message
+   *   (optional) The message to flash.
    *
    * @return \Drupal\Core\Ajax\AjaxResponse|\Symfony\Component\HttpFoundation\RedirectResponse
    *   The response object.
    */
-  protected function generateResponse(FlagInterface $flag, EntityInterface $entity, Request $request) {
+  protected function generateResponse(FlagInterface $flag, EntityInterface $entity, Request $request, $message = NULL) {
     if ($request->get(MainContentViewSubscriber::WRAPPER_FORMAT) == 'drupal_ajax') {
       // Create a new AJAX response.
       $response = new AjaxResponse();
@@ -148,15 +153,20 @@ class ActionLinkController extends ControllerBase implements ContainerInjectionI
       $replace = new ReplaceCommand($selector, $this->renderer->renderPlain($link));
       $response->addCommand($replace);
 
-      return $response;
+      if ($message) {
+        // Push a message pulsing comamnd onto the stack.
+        $pulse = new ActionLinkFlashCommand($selector, $message);
+        $response->addCommand($pulse);
+     }
     }
     else {
       // Redirect back to the entity. A passed in destination query parameter
       // will automatically override this.
       $url_info = $entity->toUrl();
-      return $this->redirect($url_info->getRouteName(), $url_info->getRouteParameters());
+      $response =  $this->redirect($url_info->getRouteName(), $url_info->getRouteParameters());
     }
 
+    return $response;
   }
 
 }
diff --git a/src/Form/FlagAddForm.php b/src/Form/FlagAddForm.php
index 01a4f7c..1903481 100644
--- a/src/Form/FlagAddForm.php
+++ b/src/Form/FlagAddForm.php
@@ -23,6 +23,10 @@ class FlagAddForm extends FlagFormBase {
   public function buildForm(array $form, FormStateInterface $form_state, $entity_type = NULL) {
     $form = parent::buildForm($form, $form_state, $entity_type);
     $form['global']['#description'] = $this->t('The scope cannot be changed once a flag has been saved.');
+
+    // While editing, the default value reflects the current link type.
+    // Here set the initial value to be an AJAX aciton link.
+    $form['display']['link_type']['#default_value'] = 'ajax_link';
     return $form;
   }
 
diff --git a/src/Plugin/ActionLink/AJAXactionLink.php b/src/Plugin/ActionLink/AJAXactionLink.php
index 7b8e531..78b090e 100644
--- a/src/Plugin/ActionLink/AJAXactionLink.php
+++ b/src/Plugin/ActionLink/AJAXactionLink.php
@@ -2,8 +2,8 @@
 
 namespace Drupal\flag\Plugin\ActionLink;
 
-use Drupal\flag\FlagInterface;
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\flag\FlagInterface;
 
 /**
  * Provides the AJAX link type.
@@ -21,9 +21,10 @@ class AJAXactionLink extends Reload {
 
   public function getAsFlagLink(FlagInterface $flag, EntityInterface $entity) {
     $build = parent::getAsFlagLink($flag, $entity);
-    $build['#attached']['library'][] = 'core/drupal.ajax';
+    $build['#attached']['library'][] = 'flag/flag.link_ajax';
     $build['#attributes']['class'][] = 'use-ajax';
     return $build;
+
   }
 
 }
diff --git a/tests/src/FunctionalJavascript/AjaxLinkTest.php b/tests/src/FunctionalJavascript/AjaxLinkTest.php
new file mode 100644
index 0000000..50b9364
--- /dev/null
+++ b/tests/src/FunctionalJavascript/AjaxLinkTest.php
@@ -0,0 +1,124 @@
+<?php
+
+namespace Drupal\Tests\flag\FunctionalJavascript;
+
+use Drupal\flag\Tests\FlagCreateTrait;
+use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
+
+/**
+ * Javascript test for AjaxLinks.
+ *
+ * When a user clicks on an AJAX link a salvo of AJAX commands is issued in
+ * response which update the DOM with a new link and a short lived message.
+ *
+ * @group flag
+ */
+class AjaxLinkTest extends JavascriptTestBase {
+
+  use FlagCreateTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = ['flag', 'node', 'user'];
+
+  /**
+   * Flag to test with.
+   *
+   * @var \Drupal\flag\FlagInterface
+   */
+  protected $flag;
+
+  /**
+   * The flag service.
+   *
+   * @var \Drupal\flag\FlagServiceInterface
+   */
+  protected $flagService;
+
+  /**
+   * Test node.
+   *
+   * @var \Drupal\node\NodeInterface
+   */
+  protected $node;
+
+  /**
+   * Admin user.
+   *
+   * @var \Drupal\user\UserInterface
+   */
+  protected $admin;
+
+  /**
+   * Normal user.
+   *
+   * @var \Drupal\user\UserInterface
+   */
+  protected $webUser;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    // A test flag.
+    $this->flag = $this->createFlag('node', ['article'], 'ajax_link');
+    $this->flagService = $this->container->get('flag');
+
+    // A article to test with.
+    $this->admin = $this->createUser([], NULL, TRUE);
+    $type = $this->createContentType(['type' => 'article']);
+    $this->node = $this->createNode([
+      'type' => 'article',
+      'uid' => $this->admin->id(),
+    ]);
+
+    $this->webUser = $this->createUser(array_keys($this->flag->actionPermissions()));
+    $this->drupalLogin($this->webUser);
+  }
+
+  /**
+   * Tests DOM update.
+   *
+   * Click on flag and then unflag links verifying that the link cycles as
+   * expected and flag flash message functions.
+   */
+  public function testDomUpdate() {
+    // Get Page.
+    $node_path = '/node/' . $this->node->id();
+    $this->drupalGet($node_path);
+    $session = $this->getSession();
+
+    // Verify initially flag link is on the page.
+    $page = $session->getPage();
+    $this->createScreenshot('/Users/martin/sites/drupal/screenshot.jpg');
+    $flag_link = $page->findLink($this->flag->getShortText('flag'));
+    $this->assertTrue($flag_link->isVisible(), 'flag link exists.');
+
+    $flag_link->click();
+
+    // Verify flags message appears.
+    $flag_message = $this->flag->getMessage('flag');
+    $p_flash = $this->assertSession()->waitForElementVisible('css', "p.js-flag-message");
+    $this->assertEquals($p_flash->getText(), $flag_message, 'DOM update: The flag message is flashed.');
+
+    // Verify new link.
+    $unflag_link = $session->getPage()->findLink($this->flag->getShortText('unflag'));
+    $this->assertTrue($unflag_link->isVisible(), 'unflag link exists.');
+
+    $unflag_link->click();
+
+    // Verfy unflag message appears.
+    $unflag_message = $this->flag->getMessage('unflag');
+    $p_flash2 = $this->assertSession()->waitForElementVisible('css', "p.js-flag-message");
+    $this->assertEquals($p_flash2->getText(), $unflag_message, 'DOM update: The unflag message is flashed.');
+
+    // Verify the cycle completes and flag returns.
+    $flag_link2 = $session->getPage()->findLink($this->flag->getShortText('flag'));
+    $this->assertTrue($flag_link2->isVisible(), 'flag cycle return to start.');
+
+  }
+
+}
diff --git a/tests/src/Unit/Ajax/ActionLinkFlashCommandTest.php b/tests/src/Unit/Ajax/ActionLinkFlashCommandTest.php
new file mode 100644
index 0000000..dde3215
--- /dev/null
+++ b/tests/src/Unit/Ajax/ActionLinkFlashCommandTest.php
@@ -0,0 +1,50 @@
+<?php
+
+namespace Drupal\Tests\flag\Unit\Ajax;
+
+use Drupal\flag\Ajax\ActionLinkFlashCommand;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * @coversDefaultClass \Drupal\flag\Ajax\ActionLinkFlashCommand
+ * @group flag
+ */
+class ActionLinkFlashCommandTest extends UnitTestCase {
+
+  /**
+   * The Random Utility.
+   *
+   * @var \Drupal\Component\Utility\Random
+   */
+  protected $random;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $this->random = $this->getRandomGenerator();
+  }
+
+  /**
+   * @covers ::render
+   */
+  public function testRender() {
+
+    // The first two characters of the CSS selector must be of the form
+    //  '\.[a-z A-Z]'.
+    $selector = '.' . $this->random->name(10, TRUE);
+
+    $message = $this->random->string(100, TRUE);
+
+    $command = new ActionLinkFlashCommand($selector, $message);
+
+    $expected = [
+      'command' => 'actionLinkFlash',
+      'selector' => $selector,
+      'message' => $message,
+    ];
+    $this->assertEquals($expected, $command->render(), 'The command was created as expected ');
+  }
+
+}
