diff --git a/README.md b/README.md
index 43e1c3f7ddc97222badc530c16fdd6f828666289..a49389f1ea9633cc0a93639db5b22846971a9d59 100644
--- a/README.md
+++ b/README.md
@@ -76,14 +76,11 @@ In this library the following validators are included:
 - `NotEmpty`: Value must not be empty
 - `Numeric`: Value must be numeric
 - `PregMatch`: Value must match regular expression `$pattern`
+- `Slug`: Value must contain only slug characters (a-z, 0-9, -, _)
 - `StrLen`: String length from value must be between `$min` and `$max`
 - `Truthful`: Converted to boolean the value must be true
 - `Url`: Value must be a valid URL
 
-Planned:
-
-- `Slug`: Value must contain only slug characters (a-z, 0-9, -, _)
-
 # Predefined Filters
 
 The following filters are included in this library:
diff --git a/src/Validator.php b/src/Validator.php
index 9df3d544ffdcf8c6377d6ead9ed661c5bedb319f..29e526bb7bddd45c4e1002a309bb6c495ccba893 100644
--- a/src/Validator.php
+++ b/src/Validator.php
@@ -31,6 +31,7 @@ use Verja\Validator\Not;
  * @method static Validator\NotEmpty notEmpty()
  * @method static Validator\Numeric numeric(string $decimalPoint = '.')
  * @method static Validator\PregMatch pregMatch(string $pattern)
+ * @method static Validator\Slug slug()
  * @method static Validator\StrLen strLen(int $min, int $max = 0)
  * @method static Validator\Truthful truthful()
  * @method static Validator\Url url(string $coverage = 'complete', $schemes = ['https', 'http', 'ftp'])
diff --git a/src/Validator/Alpha.php b/src/Validator/Alpha.php
index e6db41829613d089ad4a3465f8b12f898f003cc1..153a39b88aa972d29ae4d7709071423617bf632a 100644
--- a/src/Validator/Alpha.php
+++ b/src/Validator/Alpha.php
@@ -29,7 +29,7 @@ class Alpha extends Validator
     public function validate($value, array $context = []): bool
     {
         $regex = '/^[\pL\pM' . ($this->allowSpaces ? ' ' : '') . ']*$/u';
-        if (preg_match_all($regex, $value)) {
+        if (preg_match($regex, $value)) {
             return true;
         }
 
diff --git a/src/Validator/AlphaNumeric.php b/src/Validator/AlphaNumeric.php
index e9fde70a62966ad91e18591487cd3033f31a031a..3583184e53dd9b21f74d062cc06555ae9177130a 100644
--- a/src/Validator/AlphaNumeric.php
+++ b/src/Validator/AlphaNumeric.php
@@ -29,7 +29,7 @@ class AlphaNumeric extends Validator
     public function validate($value, array $context = []): bool
     {
         $regex = '/^[\pL\pM\pN' . ($this->allowSpaces ? ' ' : '') . ']*$/u';
-        if (preg_match_all($regex, $value)) {
+        if (preg_match($regex, $value)) {
             return true;
         }
 
diff --git a/src/Validator/Slug.php b/src/Validator/Slug.php
new file mode 100644
index 0000000000000000000000000000000000000000..9ff50bda6545236f7bb46285e38eb921c8e693ae
--- /dev/null
+++ b/src/Validator/Slug.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace Verja\Validator;
+
+use Verja\Error;
+use Verja\Validator;
+
+class Slug extends Validator
+{
+    /**
+     * Validate $value
+     *
+     * @param mixed $value
+     * @param array $context
+     * @return bool
+     */
+    public function validate($value, array $context = []): bool
+    {
+        $regex = '/^[0-9a-z-_]+$/u';
+        if (preg_match($regex, $value)) {
+            return true;
+        }
+
+        $this->error = new Error(
+            'NO_SLUG',
+            $value,
+            'value should be a valid slug'
+        );
+        return false;
+    }
+}
diff --git a/tests/Validator/AlphaNumericTest.php b/tests/Validator/AlphaNumericTest.php
index 62f536e1c770bae78ea75658bf55af2cc62779be..612849c2d040b018bfde55ee2c612d7807618fb3 100644
--- a/tests/Validator/AlphaNumericTest.php
+++ b/tests/Validator/AlphaNumericTest.php
@@ -11,7 +11,7 @@ class AlphaNumericTest extends TestCase
     /** @dataProvider provideAlphanumericStrings
      * @param $value
      * @test */
-    public function acceptsStringsWithAlphabeticalCharacters($value)
+    public function acceptsStringsWithAlphanumericCharacters($value)
     {
         $validator = new AlphaNumeric();
 
diff --git a/tests/Validator/SlugTest.php b/tests/Validator/SlugTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..5ae35c22244cf23cac78afe5aca100822aa8a2d4
--- /dev/null
+++ b/tests/Validator/SlugTest.php
@@ -0,0 +1,75 @@
+<?php
+
+namespace Verja\Test\Validator;
+
+use Verja\Error;
+use Verja\Test\TestCase;
+use Verja\Validator\Slug;
+
+class SlugTest extends TestCase
+{
+    /** @dataProvider provideSlugs
+     * @param $value
+     * @test */
+    public function acceptsStringsWithSlugs($value)
+    {
+        $validator = new Slug();
+
+        $result = $validator->validate($value);
+
+        self::assertTrue($result);
+    }
+
+    /** @dataProvider provideNonSlugs
+     * @param $value
+     * @test */
+    public function doesNotAcceptOtherCharacters($value)
+    {
+        $validator = new Slug();
+
+        $result = $validator->validate($value);
+
+        self::assertFalse($result);
+    }
+
+
+    /** @test */
+    public function storesAnErrorMessage()
+    {
+        $validator = new Slug();
+
+        $validator->validate('foo?');
+
+        self::assertEquals(
+            new Error(
+                'NO_SLUG',
+                'foo?',
+                'value should be a valid slug'
+            ),
+            $validator->getError()
+        );
+    }
+
+    public function provideSlugs()
+    {
+        return [
+            ['42'],
+            ['foobar'],
+            ['foo-bar'],
+            ['foo_bar'],
+        ];
+    }
+
+    public function provideNonSlugs()
+    {
+        return [
+            ['Û´Û²'], // Arabic 42
+            ['名'],
+            ['à'],
+            ['Müller'],
+            ['Karīna'],
+            ['string with space'],
+            [''], // empty is not valid
+        ];
+    }
+}