diff --git a/ascii-th.cabal b/ascii-th.cabal
--- a/ascii-th.cabal
+++ b/ascii-th.cabal
@@ -1,7 +1,7 @@
 cabal-version: 3.0
 
 name: ascii-th
-version: 1.1.0.0
+version: 1.1.1.0
 synopsis: Template Haskell support for ASCII
 category: Data, Text
 
@@ -28,7 +28,9 @@
     default-language: Haskell2010
     ghc-options: -Wall
     build-depends:
-        ascii-char ^>= 1.0
+        ascii-case ^>= 1.0
+      , ascii-caseless ^>= 0.0
+      , ascii-char ^>= 1.0
       , ascii-superset ^>= 1.1.0
       , base ^>= 4.14 || ^>= 4.15 || ^>= 4.16 || ^>= 4.17
 
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,3 +1,17 @@
+### 1.1.1.0 (2023-01-03)
+
+New in `ASCII.QuasiQuoters`:
+
+- `caseless`
+- `upper`
+- `lower`
+
+New in `ASCII.TemplateHaskell`:
+
+- `caselessListExp`
+- `caselessListPat`
+- `caselessIsStringPat`
+
 ### 1.1.0.0 (2023-01-03)
 
 Change `ascii-superset` version from 1.0 to 1.1
diff --git a/library/ASCII/QuasiQuoters.hs b/library/ASCII/QuasiQuoters.hs
--- a/library/ASCII/QuasiQuoters.hs
+++ b/library/ASCII/QuasiQuoters.hs
@@ -6,21 +6,29 @@
 -}
 module ASCII.QuasiQuoters
   (
-    char,
-    string,
+    {- * Character -} char,
+    {- * String -} string,
+    {- * Caseless string -} caseless,
+    {- * Upper-case string -} upper,
+    {- * Lower-case string -} lower,
   )
   where
 
+import ASCII.Case (Case (..))
+import ASCII.Caseless (CaselessChar)
 import ASCII.Char (Char)
-import ASCII.Superset (toCharListMaybe, toCharMaybe)
-import ASCII.TemplateHaskell (isCharExp, isCharPat, isStringExp, isStringPat)
 import Control.Monad (return, (>=>))
 import Control.Monad.Fail (MonadFail, fail)
+import Data.Functor ((<$>))
 import Data.Maybe (Maybe (..))
 import Language.Haskell.TH.Quote (QuasiQuoter (..))
 import Language.Haskell.TH.Syntax (Exp, Pat, Q)
 
+import qualified ASCII.Case as Case
+import qualified ASCII.Superset as S
+import qualified ASCII.TemplateHaskell as TH
 import qualified Data.Char as Unicode
+import qualified Data.List as List
 import qualified Data.String as Unicode
 
 {-| An expression pattern corresponding to an ASCII character
@@ -58,7 +66,7 @@
 -}
 
 char :: QuasiQuoter
-char = expPatQQ requireOneAscii isCharExp isCharPat
+char = expPatQQ requireOneAscii TH.isCharExp TH.isCharPat
 
 {- | An expression or pattern corresponding to an ASCII string
 
@@ -100,22 +108,146 @@
 -}
 
 string :: QuasiQuoter
-string = expPatQQ requireAsciiList isStringExp isStringPat
+string = expPatQQ requireAsciiList TH.isStringExp TH.isStringPat
 
+{-| An expression or pattern corresponding to a case-insensitive ASCII string
+
+=== In an expression context
+
+A monomorphic expression of type @['CaselessChar']@.
+
+@
+[caseless|Hello!|] ==
+    [LetterH, LetterE, LetterL, LetterL, LetterO, ExclamationMark]
+@
+
+=== In a pattern context
+
+A case-insensitive match of any type belonging to the
+'ASCII.Superset.ToCaselessString' class.
+
+@
+let
+    x = case "Hello!" :: 'Text' of
+          [caseless|Bye!|] -> 1
+          [caseless|hEllo!|] -> 2
+          _ -> 3
+in
+    x == 2
+@
+
+-}
+caseless :: QuasiQuoter
+caseless = expPatQQ requireAsciiListCI TH.caselessListExp TH.caselessIsStringPat
+
+{-| An expression or pattern corresponding to an ASCII string where all the
+letters are of lower case
+
+The letters in the body of the quasi-quotation may be written in any case
+you like; they will be converted to lower case automatically.
+
+=== In an expression context
+
+The expression can become any type belonging to the 'ASCII.Superset.FromString'
+class. Any letters in the quoted content will be converted to lower case.
+
+@
+[lower|Hello!|] == ("hello!" :: 'Text')
+@
+
+=== In a pattern context
+
+The pattern matches a value of a type satisfying the 'ASCII.Superset.ToString'
+constraint. A value matches this pattern if:
+
+* All of the letters in the tested value are in lower case
+* The tested value satisfies a case-insensitive comparison
+  with the quasi-quoted content
+
+@
+let
+    x = case "hi!" :: 'Text' of
+          [lower|wow|] -> 1
+          [lower|Hi!|] -> 2
+          _ -> 3
+in
+    x == 2
+@
+
+-}
+lower :: QuasiQuoter
+lower = ofCase LowerCase
+
+{-| An expression or pattern corresponding to an ASCII string where all the
+letters are of upper case
+
+The letters in the body of the quasi-quotation may be written in any case
+you like; they will be converted to upper case automatically.
+
+=== In an expression context
+
+The expression can become any type belonging to the 'ASCII.Superset.FromString'
+class. Any letters in the quoted content will be converted to upper case.
+
+@
+[upper|Hello!|] == ("HELLO!" :: 'Text')
+@
+
+=== In a pattern context
+
+The pattern matches a value of a type satisfying the 'ASCII.Superset.ToString'
+constraint. A value matches this pattern if:
+
+* All of the letters in the tested value are in upper case
+* The tested value satisfies a case-insensitive comparison
+  with the quasi-quoted content
+
+@
+let
+    x = case "HI!" :: 'Text' of
+          [QQ.upper|wow|] -> 1
+          [QQ.upper|Hi!|] -> 2
+          _ -> 3
+in
+    x == 2
+@
+
+-}
+upper :: QuasiQuoter
+upper = ofCase UpperCase
+
+ofCase :: Case -> QuasiQuoter
+ofCase c = expPatQQ (requireAsciiToCase c) TH.isStringExp TH.isStringPat
+
+{-| Require the string to consist of exactly one ASCII character -}
 requireOneAscii :: Unicode.String -> Q Char
 requireOneAscii = requireOne >=> requireAscii
 
+{-| Require the list to consist of exactly one element -}
 oneMaybe :: [a] -> Maybe a
 oneMaybe xs = case xs of [x] -> Just x; _ -> Nothing
 
+{-| Require the string to consist of exactly one character -}
 requireOne :: Unicode.String -> Q Unicode.Char
 requireOne = oneMaybe || "Must be exactly one character."
 
+{-| Require the character to be ASCII -}
 requireAscii :: Unicode.Char -> Q Char
-requireAscii = toCharMaybe || "Must be an ASCII character."
+requireAscii = S.toCharMaybe || "Must be an ASCII character."
 
+{-| Require the string to consist of all ASCII characters -}
 requireAsciiList :: Unicode.String -> Q [Char]
-requireAsciiList = toCharListMaybe || "Must be only ASCII characters."
+requireAsciiList = S.toCharListMaybe || "Must be only ASCII characters."
+
+{-| Require the string to consist of all ASCII characters,
+and return them with letter case discarded -}
+requireAsciiListCI :: Unicode.String -> Q [CaselessChar]
+requireAsciiListCI = S.toCaselessCharListMaybe || "Must be only ASCII characters."
+
+{-| Require the string to consist of all ASCII characters,
+and return them converted to the given case -}
+requireAsciiToCase :: Case -> Unicode.String -> Q [Char]
+requireAsciiToCase c s = List.map (Case.toCase c) <$> requireAsciiList s
 
 (||) :: (a -> Maybe b) -> Unicode.String -> a -> Q b
 f || msg = \a -> case f a of Just b -> return b; Nothing -> fail msg
diff --git a/library/ASCII/TemplateHaskell.hs b/library/ASCII/TemplateHaskell.hs
--- a/library/ASCII/TemplateHaskell.hs
+++ b/library/ASCII/TemplateHaskell.hs
@@ -1,15 +1,21 @@
 module ASCII.TemplateHaskell
   (
-    {- * Characters          -} charExp,     charPat,
-    {- * Character lists     -} charListExp, charListPat,
-    {- * Character supersets -} isCharExp,   isCharPat,
-    {- * String supersets    -} isStringExp, isStringPat,
+    {- * Monomorphic -}
+    {- ** Character -} charExp, charPat,
+    {- ** String -} charListExp, charListPat,
+    {- ** Caseless string -} caselessListExp, caselessListPat,
+
+    {- * Polymorphic -}
+    {- ** Character -} isCharExp, isCharPat,
+    {- ** String -} isStringExp, isStringPat,
+    {- ** Caseless string -} caselessIsStringPat,
   )
   where
 
 import qualified ASCII.Char as ASCII
 import qualified ASCII.Superset as S
 
+import ASCII.Caseless (CaselessChar)
 import Data.Data (Data)
 import Data.Maybe (Maybe (..))
 import Language.Haskell.TH.Syntax (Exp, Pat, Q, dataToExpQ, dataToPatQ)
@@ -88,6 +94,12 @@
 
 -}
 
+caselessListExp :: [CaselessChar] -> Q Exp
+caselessListExp = exp
+
+caselessListPat :: [CaselessChar] -> Q Pat
+caselessListPat = pat
+
 isCharExp :: ASCII.Char -> Q Exp
 isCharExp x = [| S.fromChar $(charExp x) |]
 
@@ -115,3 +127,8 @@
 {-| Pattern that matches a type with a 'S.ToString' constraint -}
 isStringPat :: [ASCII.Char] -> Q Pat
 isStringPat xs = [p| (S.toCharListMaybe -> Just $(charListPat xs)) |]
+
+{-| Matches a value of any type belonging to the 'S.ToCaselessString'
+class, as if it were a list of 'CaselessChar' -}
+caselessIsStringPat :: [CaselessChar] -> Q Pat
+caselessIsStringPat xs = [p| (S.toCaselessCharListMaybe -> Just $(caselessListPat xs)) |]
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -1,8 +1,7 @@
 module Main (main) where
 
-import ASCII.QuasiQuoters (char, string)
-import ASCII.TemplateHaskell (charExp, charListExp, charListPat, charPat,
-                              isCharExp, isCharPat)
+import qualified ASCII.QuasiQuoters as QQ
+import qualified ASCII.TemplateHaskell as TH
 
 import ASCII.Char (Char (..))
 import ASCII.Refinement (ASCII, asciiUnsafe)
@@ -14,6 +13,7 @@
 import Prelude (Integer)
 import System.IO (IO)
 
+import qualified ASCII.Caseless as Caseless
 import qualified Data.ByteString.Builder as BS.Builder
 import qualified Data.ByteString.Lazy as LBS
 
@@ -22,62 +22,119 @@
 main :: IO ()
 main = hspec $ do
 
-    describe "char quasi-quoter" $ do
-        it "can be ASCII.Char" $ shouldBe @Char [char|e|] SmallLetterE
-        it "can be Word8" $ shouldBe @Word8 [char|e|] 101
-        it "can be a pattern" $ do
-            let x = case Tilde of [char|@|] -> 1; [char|~|] -> 2; _ -> 3
-            shouldBe @Integer x 2
+    describe "ASCII.QuasiQuoters" $ do
 
-    describe "string quasi-quoter" $ do
-        it "can be [ASCII.Char]" $ shouldBe @[Char] [string|Hello!|]
-            [CapitalLetterH, SmallLetterE, SmallLetterL,
-             SmallLetterL, SmallLetterO, ExclamationMark]
-        it "can be String" $ shouldBe @String [string|Hello!|] "Hello!"
-        it "can be Text" $ shouldBe @Text [string|Hello!|] "Hello!"
-        it "can be bytestring Builder" $ shouldBe @LBS.ByteString
-            (BS.Builder.toLazyByteString [string|Hello!|]) "Hello!"
-        it "can be a pattern" $ do
-            let x = case [CapitalLetterH, SmallLetterI] of
-                      [string|Bye|] -> 1; [string|Hi|] -> 2; _ -> 3
-            shouldBe @Integer x 2
+        describe "char" $ do
+            it "can be ASCII.Char" $ shouldBe @Char [QQ.char|e|] SmallLetterE
+            it "can be Word8" $ shouldBe @Word8 [QQ.char|e|] 101
+            it "can be a pattern" $ do
+                let x = case Tilde of [QQ.char|@|] -> 1; [QQ.char|~|] -> 2; _ -> 3
+                shouldBe @Integer x 2
 
-    describe "charExp" $
-        it "is a Char expression" $
-            shouldBe @Char $(charExp CapitalLetterF) CapitalLetterF
+        describe "string" $ do
+            it "can be [ASCII.Char]" $ shouldBe @[Char] [QQ.string|Hello!|]
+                [CapitalLetterH, SmallLetterE, SmallLetterL,
+                SmallLetterL, SmallLetterO, ExclamationMark]
+            it "can be String" $ shouldBe @String [QQ.string|Hello!|] "Hello!"
+            it "can be Text" $ shouldBe @Text [QQ.string|Hello!|] "Hello!"
+            it "can be bytestring Builder" $ shouldBe @LBS.ByteString
+                (BS.Builder.toLazyByteString [QQ.string|Hello!|]) "Hello!"
+            it "can be a pattern" $ do
+                let x = case [CapitalLetterH, SmallLetterI] of
+                          [QQ.string|Bye|] -> 1; [QQ.string|Hi|] -> 2; _ -> 3
+                shouldBe @Integer x 2
 
-    describe "charPat" $ do
-        it "is a Char pattern" $ do
-            let x = case SmallLetterS of $(charPat SmallLetterR) -> 1;
-                                         $(charPat SmallLetterS) -> 2;
-                                         _ -> 3
-            shouldBe @Integer x 2
+        describe "caseless" $ do
+            it "can be [CaselessChar]" $ shouldBe [QQ.caseless|Hello!|]
+                [Caseless.LetterH, Caseless.LetterE, Caseless.LetterL,
+                Caseless.LetterL, Caseless.LetterO, Caseless.ExclamationMark]
+            it "can be a pattern over [CaselessChar]" $ do
+                let x = case [Caseless.LetterH, Caseless.LetterI] of
+                          [QQ.caseless|Bye|] -> 1; [QQ.caseless|Hi|] -> 2; _ -> 3
+                shouldBe @Integer x 2
+            it "can be a pattern over Text" $ do
+                let x = case "Hello!" :: Text of
+                          [QQ.caseless|Bye!|] -> 1; [QQ.caseless|Hello!|] -> 2; _ -> 3
+                shouldBe @Integer x 2
+            it "matches Text in a case-insensitive manner" $ do
+                let x = case "Hello!" :: Text of
+                          [QQ.caseless|Bye!|] -> 1; [QQ.caseless|hEllo!|] -> 2; _ -> 3
+                shouldBe @Integer x 2
 
-    describe "charListExp" $ do
-        it "is a [Char] expression" $ shouldBe @[Char]
-            $(charListExp [CapitalLetterH, SmallLetterI])
-            [CapitalLetterH, SmallLetterI]
+        describe "upper" $ do
+            it "can be Text" $ shouldBe [QQ.upper|Hello!|] ("HELLO!" :: Text)
+            it "can match Text" $ do
+                let x = case "HI!" :: Text of
+                          [QQ.upper|wow|] -> 1
+                          [QQ.upper|Hi!|] -> 2
+                          _ -> 3
+                shouldBe @Integer x 2
+            it "only matches all upper-case Text" $ do
+                let x = case "Hi!" :: Text of
+                          [QQ.upper|Hi!|] -> 1
+                          _ -> 2
+                shouldBe @Integer x 2
 
-    describe "charListPat" $ do
-        it "is a [Char] pattern" $ do
-            let x = case [CapitalLetterH, SmallLetterI] of
-                      $(charListPat [CapitalLetterH, SmallLetterA]) -> 1
-                      $(charListPat [CapitalLetterH, SmallLetterI]) -> 2
-                      _ -> 3
-            shouldBe @Integer x 2
+        describe "lower" $ do
+            it "can be Text" $ shouldBe [QQ.lower|Hello!|] ("hello!" :: Text)
+            it "can match Text" $ do
+                let x = case "hi!" :: Text of
+                          [QQ.lower|wow|] -> 1
+                          [QQ.lower|Hi!|] -> 2
+                          _ -> 3
+                shouldBe @Integer x 2
+            it "only matches all lower-case Text" $ do
+                let x = case "Hi!" :: Text of
+                          [QQ.lower|Hi!|] -> 1
+                          _ -> 2
+                shouldBe @Integer x 2
 
-    describe "isCharExp" $ do
-        it "can be ASCII.Char expression" $
-            shouldBe @Char $(isCharExp CapitalLetterA) CapitalLetterA
-        it "can be a Word8 expression" $
-            shouldBe @Word8 $(isCharExp CapitalLetterA) 65
-        it "can be an ASCII Word8 expression" $
-            shouldBe @(ASCII Word8)
-                $(isCharExp CapitalLetterA) (asciiUnsafe 65)
+    describe "ASCII.TemplateHaskell" $ do
 
-    describe "isCharPat" $ do
-        it "can be a Word8 pattern" $ do
-            let x = case (66 :: Word8) of $(isCharPat CapitalLetterA) -> 1
-                                          $(isCharPat CapitalLetterB) -> 2
-                                          _ -> 3
-            shouldBe @Word8 x 2
+        describe "charExp" $
+            it "is a Char expression" $
+                shouldBe @Char $(TH.charExp CapitalLetterF) CapitalLetterF
+
+        describe "charPat" $ do
+            it "is a Char pattern" $ do
+                let x = case SmallLetterS of $(TH.charPat SmallLetterR) -> 1;
+                                             $(TH.charPat SmallLetterS) -> 2;
+                                             _ -> 3
+                shouldBe @Integer x 2
+
+        describe "charListExp" $ do
+            it "is a [Char] expression" $ shouldBe @[Char]
+                $(TH.charListExp [CapitalLetterH, SmallLetterI])
+                [CapitalLetterH, SmallLetterI]
+
+        describe "charListPat" $ do
+            it "is a [Char] pattern" $ do
+                let x = case [CapitalLetterH, SmallLetterI] of
+                          $(TH.charListPat [CapitalLetterH, SmallLetterA]) -> 1
+                          $(TH.charListPat [CapitalLetterH, SmallLetterI]) -> 2
+                          _ -> 3
+                shouldBe @Integer x 2
+
+        describe "isCharExp" $ do
+            it "can be ASCII.Char expression" $
+                shouldBe @Char $(TH.isCharExp CapitalLetterA) CapitalLetterA
+            it "can be a Word8 expression" $
+                shouldBe @Word8 $(TH.isCharExp CapitalLetterA) 65
+            it "can be an ASCII Word8 expression" $
+                shouldBe @(ASCII Word8)
+                    $(TH.isCharExp CapitalLetterA) (asciiUnsafe 65)
+
+        describe "isCharPat" $ do
+            it "can be a Word8 pattern" $ do
+                let x = case (66 :: Word8) of $(TH.isCharPat CapitalLetterA) -> 1
+                                              $(TH.isCharPat CapitalLetterB) -> 2
+                                              _ -> 3
+                shouldBe @Integer x 2
+
+        describe "caselessIsStringPat" $ do
+            it "matches a cased string regardless of its case" $ do
+                let x = case [QQ.string|Hi!|] :: Text of
+                      $(TH.caselessIsStringPat [Caseless.LetterG, Caseless.LetterO, Caseless.FullStop]) -> 1
+                      $(TH.caselessIsStringPat [Caseless.LetterH, Caseless.LetterI, Caseless.ExclamationMark]) -> 2
+                      _ -> 3
+                shouldBe @Integer x 2
