diff --git a/ASCII/QuasiQuoters.hs b/ASCII/QuasiQuoters.hs
new file mode 100644
--- /dev/null
+++ b/ASCII/QuasiQuoters.hs
@@ -0,0 +1,120 @@
+module ASCII.QuasiQuoters ( char, string ) where
+
+import ASCII.Char                  ( Char )
+import ASCII.Superset              ( toCharMaybe, toCharListMaybe )
+import ASCII.TemplateHaskell       ( isCharExp, isCharPat, isStringExp, isStringPat )
+import Control.Monad               ( (>=>), return )
+import Control.Monad.Fail          ( MonadFail, fail )
+import Data.Maybe                  ( Maybe (..) )
+import Language.Haskell.TH.Quote   ( QuasiQuoter (..) )
+import Language.Haskell.TH.Syntax  ( Q, Exp, Pat )
+
+import qualified Data.Char   as Unicode
+import qualified Data.String as Unicode
+
+{- $setup
+
+>>> :set -fno-warn-overlapping-patterns
+>>> :set -XNoQuasiQuotes
+>>> :set -XNoViewPatterns
+>>> import qualified ASCII
+>>> import qualified Data.String
+>>> import qualified Data.Text
+>>> import qualified Data.ByteString.Builder
+>>> import Data.Word (Word8)
+>>> import ASCII.Char
+>>> import ASCII.QuasiQuoters
+
+-}
+
+{- | Produces an expression or a pattern corresponding to an ASCII character.
+
+The result will have an 'ASCII.Superset.IsChar' constraint; since this is polymorphic, use with a type signature to specify the particular you want is recommended.
+
+The quasi-quoted string must consist of a single character that is within the ASCII character set.
+
+>>> :set -XQuasiQuotes
+
+>>> [char|e|] :: ASCII.Char
+SmallLetterE
+
+>>> [char|e|] :: Word8
+101
+
+Use in a pattern context requires enabling the @ViewPatterns@ language extension.
+
+>>> :set -XViewPatterns
+
+>>> case Tilde of [char|@|] -> 1; [char|~|] -> 2; _ -> 3
+2
+
+-}
+
+char :: QuasiQuoter
+char = expPatQQ requireOneAscii isCharExp isCharPat
+
+{- | Produces an expression or a pattern corresponding to an ASCII string.
+
+The result will have an 'ASCII.Superset.IsString' constraint; since this is polymorphic, use with a type signature to specify the particular you want is recommended.
+
+The quasi-quoted string must consist only of characters are within the ASCII character set.
+
+>>> :set -XQuasiQuotes
+
+>>> [string|Hello!|] :: [ASCII.Char]
+[CapitalLetterH,SmallLetterE,SmallLetterL,SmallLetterL,SmallLetterO,ExclamationMark]
+
+>>> [string|Hello!|] :: Data.String.String
+"Hello!"
+
+>>> [string|Hello!|] :: Data.Text.Text
+"Hello!"
+
+>>> Data.ByteString.Builder.toLazyByteString [string|Hello!|]
+"Hello!"
+
+
+Use in a pattern context requires enabling the @ViewPatterns@ language extension.
+
+>>> :set -XViewPatterns
+
+>>> case [CapitalLetterH, SmallLetterI] of [string|Bye|] -> 1; [string|Hi|] -> 2; _ -> 3
+2
+
+-}
+
+string :: QuasiQuoter
+string = expPatQQ requireAsciiList isStringExp isStringPat
+
+requireOneAscii :: Unicode.String -> Q Char
+requireOneAscii = requireOne >=> requireAscii
+
+oneMaybe :: [a] -> Maybe a
+oneMaybe xs = case xs of [x] -> Just x; _ -> Nothing
+
+requireOne :: Unicode.String -> Q Unicode.Char
+requireOne = oneMaybe || "Must be exactly one character."
+
+requireAscii :: Unicode.Char -> Q Char
+requireAscii = toCharMaybe || "Must be an ASCII character."
+
+requireAsciiList :: Unicode.String -> Q [Char]
+requireAsciiList = toCharListMaybe || "Must be only ASCII characters."
+
+(||) :: (a -> Maybe b) -> Unicode.String -> a -> Q b
+f || msg = \a -> case f a of Just b -> return b; Nothing -> fail msg
+
+expPatQQ :: (Unicode.String -> Q a) -> (a -> Q Exp) -> (a -> Q Pat) -> QuasiQuoter
+expPatQQ f a b =
+    QuasiQuoter
+        { quoteExp  = f >=> a
+        , quotePat  = f >=> b
+        , quoteType = notType
+        , quoteDec  = notDec
+        }
+
+notType :: MonadFail m => a -> m b
+notType _ = fail "Cannot be used in a type context."
+
+notDec :: MonadFail m => a -> m b
+notDec _ = fail "Cannot be used in a declaration context."
diff --git a/ASCII/TemplateHaskell.hs b/ASCII/TemplateHaskell.hs
new file mode 100644
--- /dev/null
+++ b/ASCII/TemplateHaskell.hs
@@ -0,0 +1,135 @@
+module ASCII.TemplateHaskell (
+
+    {- * Characters          -} charExp,     charPat,
+    {- * Character lists     -} charListExp, charListPat,
+    {- * Character supersets -} isCharExp,   isCharPat,
+    {- * String supersets    -} isStringExp, isStringPat
+
+  ) where
+
+import qualified ASCII.Char       as  ASCII
+import qualified ASCII.Superset   as  S
+
+import Data.Data                  ( Data )
+import Data.Maybe                 ( Maybe (..) )
+import Language.Haskell.TH.Syntax ( Q, Exp, Pat, dataToExpQ, dataToPatQ )
+
+{- $setup
+
+>>> :set -XNoViewPatterns
+>>> import ASCII.Char (Char (..))
+>>> import ASCII.Refinement (ASCII)
+>>> import ASCII.Superset (toCharOrFail)
+>>> import ASCII.TemplateHaskell (charExp)
+>>> import Control.Monad ((>>=))
+>>> import Data.Word (Word8)
+
+-}
+
+exp :: Data a => a -> Q Exp
+exp = dataToExpQ (\_ -> Nothing)
+
+pat :: Data a => a -> Q Pat
+pat = dataToPatQ (\_ -> Nothing)
+
+{- |
+
+>>> $(toCharOrFail 'F' >>= charExp)
+CapitalLetterF
+
+>>> $(toCharOrFail '\DEL' >>= charExp)
+Delete
+
+-}
+
+charExp :: ASCII.Char -> Q Exp
+charExp = exp
+
+{- |
+
+>>> :{
+>>> case SmallLetterS of
+>>>     $(toCharOrFail 'r' >>= charPat) -> 1
+>>>     $(toCharOrFail 's' >>= charPat) -> 2
+>>>     _                               -> 3
+>>> :}
+2
+
+This is the same as:
+
+>>> :{
+>>> case SmallLetterS of
+>>>     SmallLetterR -> 1
+>>>     SmallLetterS -> 2
+>>>     _            -> 3
+>>> :}
+2
+
+-}
+
+charPat :: ASCII.Char -> Q Pat
+charPat = pat
+
+{- |
+
+>>> $(charListExp [CapitalLetterH, SmallLetterI])
+[CapitalLetterH,SmallLetterI]
+
+-}
+
+charListExp :: [ASCII.Char] -> Q Exp
+charListExp = exp
+
+{- |
+
+>>> :{
+>>> case [CapitalLetterH, SmallLetterI] of
+>>>     $(charListPat [CapitalLetterH, SmallLetterA]) -> 1
+>>>     $(charListPat [CapitalLetterH, SmallLetterI]) -> 2
+>>>     _                                             -> 3
+>>> :}
+2
+
+-}
+
+charListPat :: [ASCII.Char] -> Q Pat
+charListPat = pat
+
+{- |
+
+>>> $(isCharExp CapitalLetterA) :: ASCII.Char
+CapitalLetterA
+
+>>> $(isCharExp CapitalLetterA) :: Word8
+65
+
+>>> $(isCharExp CapitalLetterA) :: ASCII Word8
+asciiUnsafe 65
+
+-}
+
+isCharExp :: ASCII.Char -> Q Exp
+isCharExp x = [| S.fromChar $(charExp x) |]
+
+{- |
+
+>>> :set -XViewPatterns
+
+>>> :{
+>>> case (66 :: Word8) of
+>>>     $(isCharPat CapitalLetterA) -> 1
+>>>     $(isCharPat CapitalLetterB) -> 2
+>>>     _                           -> 3
+>>> :}
+2
+
+-}
+
+isCharPat :: ASCII.Char -> Q Pat
+isCharPat x = [p| (S.toCharMaybe -> Just $(charPat x)) |]
+
+isStringExp :: [ASCII.Char] -> Q Exp
+isStringExp xs = [| S.fromCharList $(charListExp xs) |]
+
+isStringPat :: [ASCII.Char] -> Q Pat
+isStringPat xs = [p| (S.toCharListMaybe -> Just $(charListPat xs)) |]
diff --git a/ascii-th.cabal b/ascii-th.cabal
new file mode 100644
--- /dev/null
+++ b/ascii-th.cabal
@@ -0,0 +1,41 @@
+cabal-version: 2.0
+
+name: ascii-th
+version: 1.0.0.0
+synopsis: Template Haskell support for ASCII
+category: Data, Text
+
+description: This package defines Template Haskell support for ASCII, including quasi-quoters for expressing ASCII strings.
+
+license: Apache-2.0
+license-file: license.txt
+
+author: Chris Martin
+maintainer: Chris Martin, Julie Moronuki
+
+homepage:    https://github.com/typeclasses/ascii
+bug-Reports: https://github.com/typeclasses/ascii/issues
+
+build-type: Simple
+
+tested-with: GHC == 8.8.1, GHC == 8.6.5, GHC == 8.4.3
+
+source-repository head
+    type:     git
+    location: git://github.com/typeclasses/ascii.git
+
+library
+    default-language: Haskell2010
+    default-extensions: NoImplicitPrelude
+    default-extensions: TemplateHaskell
+    default-extensions: QuasiQuotes
+    default-extensions: ViewPatterns
+    ghc-options: -Wall
+
+    build-depends: ascii-char       >= 1.0  && < 1.1
+    build-depends: ascii-superset   >= 1.0  && < 1.1
+    build-depends: base             >= 4.11 && < 4.14
+    build-depends: template-haskell >= 2.13 && < 2.16
+
+    exposed-modules: ASCII.TemplateHaskell
+    exposed-modules: ASCII.QuasiQuoters
diff --git a/license.txt b/license.txt
new file mode 100644
--- /dev/null
+++ b/license.txt
@@ -0,0 +1,13 @@
+Copyright 2020 Typeclass Consulting LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
