diff --git a/IHP/HSX/HaskellParser.hs b/IHP/HSX/HaskellParser.hs
new file mode 100644
--- /dev/null
+++ b/IHP/HSX/HaskellParser.hs
@@ -0,0 +1,53 @@
+module IHP.HSX.HaskellParser (parseHaskellExpression) where
+
+import Prelude
+import GHC.Parser.Lexer (ParseResult (..), PState (..))
+import qualified GHC.Parser.Errors.Ppr as ParserErrorPpr
+import GHC.Types.SrcLoc
+import qualified GHC.Parser as Parser
+import qualified GHC.Parser.Lexer as Lexer
+import GHC.Data.FastString
+import GHC.Data.StringBuffer
+import GHC.Parser.PostProcess
+import Text.Megaparsec.Pos
+import qualified "template-haskell" Language.Haskell.TH as TH
+
+import qualified GHC.Data.EnumSet as EnumSet
+import GHC
+import IHP.HSX.HsExpToTH (toExp)
+
+parseHaskellExpression :: SourcePos -> [TH.Extension] -> String -> Either (Int, Int, String) TH.Exp
+parseHaskellExpression sourcePos extensions input =
+        case expr of
+            POk parserState result -> Right (toExp (unLoc result))
+            PFailed parserState ->
+                let
+                    error = concatMap (show . ParserErrorPpr.pprError) (parserState.errors)
+                    realLoc = (psRealLoc parserState.loc)
+                    line = srcLocLine realLoc
+                    col = srcLocCol realLoc
+                in
+                    Left (line, col, error)
+    where
+        expr :: ParseResult (LocatedA (HsExpr GhcPs))
+        expr = case Lexer.unP Parser.parseExpression parseState of
+                POk parserState result -> Lexer.unP (runPV (unECP result)) parserState
+                PFailed parserState -> PFailed parserState
+
+        location :: RealSrcLoc
+        location = mkRealSrcLoc filename line col
+        
+        filename :: FastString
+        filename = mkFastString sourcePos.sourceName
+
+        line :: Int
+        line = unPos sourcePos.sourceLine
+
+        col :: Int
+        col = unPos sourcePos.sourceColumn
+
+        buffer = stringToStringBuffer input
+        parseState = Lexer.initParserState parserOpts buffer location
+
+        parserOpts :: Lexer.ParserOpts
+        parserOpts = Lexer.mkParserOpts EnumSet.empty (EnumSet.fromList extensions) False False False False
diff --git a/IHP/HSX/HsExpToTH.hs b/IHP/HSX/HsExpToTH.hs
new file mode 100644
--- /dev/null
+++ b/IHP/HSX/HsExpToTH.hs
@@ -0,0 +1,201 @@
+{-# LANGUAGE ViewPatterns #-}
+{-|
+Module: IHP.HSX.HsExpToTH
+Copyright: (c) digitally induced GmbH, 2022
+Description: Converts Haskell AST to Template Haskell AST
+
+Based on https://github.com/guibou/PyF/blob/b3aaee12d34380e55aa3909690041eccb8fcf001/src/PyF/Internal/Meta.hs
+-}
+module IHP.HSX.HsExpToTH (toExp) where
+
+import Prelude
+
+import GHC.Hs.Expr as Expr
+import GHC.Hs.Extension as Ext
+import GHC.Hs.Pat as Pat
+import GHC.Hs.Lit
+import qualified Data.ByteString as B
+import qualified Language.Haskell.TH.Syntax as TH
+import GHC.Types.SrcLoc
+import GHC.Types.Name
+import GHC.Types.Name.Reader
+import GHC.Data.FastString
+import GHC.Utils.Outputable (Outputable, ppr, showSDocUnsafe)
+import GHC.Types.Basic (Boxity(..))
+import GHC.Types.SourceText (il_value, rationalFromFractionalLit)
+import qualified GHC.Unit.Module as Module
+import GHC.Stack
+import qualified Data.List.NonEmpty as NonEmpty
+import Language.Haskell.Syntax.Type
+
+fl_value = rationalFromFractionalLit
+
+toLit :: HsLit GhcPs -> TH.Lit
+toLit (HsChar _ c) = TH.CharL c
+toLit (HsCharPrim _ c) = TH.CharPrimL c
+toLit (HsString _ s) = TH.StringL (unpackFS s)
+toLit (HsStringPrim _ s) = TH.StringPrimL (B.unpack s)
+toLit (HsInt _ i) = TH.IntegerL (il_value i)
+toLit (HsIntPrim _ i) = TH.IntPrimL i
+toLit (HsWordPrim _ i) = TH.WordPrimL i
+toLit (HsInt64Prim _ i) = TH.IntegerL i
+toLit (HsWord64Prim _ i) = TH.WordPrimL i
+toLit (HsInteger _ i _) = TH.IntegerL i
+toLit (HsRat _ f _) = TH.FloatPrimL (fl_value f)
+toLit (HsFloatPrim _ f) = TH.FloatPrimL (fl_value f)
+toLit (HsDoublePrim _ f) = TH.DoublePrimL (fl_value f)
+
+toLit' :: OverLitVal -> TH.Lit
+toLit' (HsIntegral i) = TH.IntegerL (il_value i)
+toLit' (HsFractional f) = TH.RationalL (fl_value f)
+toLit' (HsIsString _ fs) = TH.StringL (unpackFS fs)
+
+toType :: HsType GhcPs -> TH.Type
+toType (HsWildCardTy _) = TH.WildCardT
+toType (HsTyVar _ _ n) =
+  let n' = unLoc n
+   in if isRdrTyVar n'
+        then TH.VarT (toName n')
+        else TH.ConT (toName n')
+toType t = todo "toType" t
+
+toName :: RdrName -> TH.Name
+toName n = case n of
+  (Unqual o) -> TH.mkName (occNameString o)
+  (Qual m o) -> TH.mkName (Module.moduleNameString m <> "." <> occNameString o)
+  (Orig _ _) -> error "orig"
+  (Exact _) -> error "exact"
+
+toFieldExp :: a
+toFieldExp = undefined
+
+toPat :: Pat.Pat GhcPs -> TH.Pat
+toPat (Pat.VarPat _ (unLoc -> name)) = TH.VarP (toName name)
+toPat (TuplePat _ p _) = TH.TupP (map (toPat . unLoc) p)
+toPat p = todo "toPat" p
+
+toExp :: Expr.HsExpr GhcPs -> TH.Exp
+toExp (Expr.HsVar _ n) =
+  let n' = unLoc n
+   in if isRdrDataCon n'
+        then TH.ConE (toName n')
+        else TH.VarE (toName n')
+
+toExp (Expr.HsUnboundVar _ n)              = TH.UnboundVarE (TH.mkName . occNameString $ n)
+
+toExp Expr.HsIPVar {}
+  = noTH "toExp" "HsIPVar"
+
+toExp (Expr.HsLit _ l)
+  = TH.LitE (toLit l)
+
+toExp (Expr.HsOverLit _ OverLit {ol_val})
+  = TH.LitE (toLit' ol_val)
+
+toExp (Expr.HsApp _ e1 e2)
+  = TH.AppE (toExp . unLoc $ e1) (toExp . unLoc $ e2)
+
+toExp (Expr.HsAppType _ e HsWC {hswc_body}) = TH.AppTypeE (toExp . unLoc $ e) (toType . unLoc $ hswc_body)
+toExp (Expr.ExprWithTySig _ e HsWC{hswc_body=unLoc -> HsSig{sig_body}}) = TH.SigE (toExp . unLoc $ e) (toType . unLoc $ sig_body)
+
+toExp (Expr.OpApp _ e1 o e2)
+  = TH.UInfixE (toExp . unLoc $ e1) (toExp . unLoc $ o) (toExp . unLoc $ e2)
+
+toExp (Expr.NegApp _ e _)
+  = TH.AppE (TH.VarE 'negate) (toExp . unLoc $ e)
+
+-- NOTE: for lambda, there is only one match
+toExp (Expr.HsLam _ (Expr.MG _ (unLoc -> (map unLoc -> [Expr.Match _ _ (map unLoc -> ps) (Expr.GRHSs _ [unLoc -> Expr.GRHS _ _ (unLoc -> e)] _)])) _))
+  = TH.LamE (fmap toPat ps) (toExp e)
+
+-- toExp (Expr.Let _ bs e)                       = TH.LetE (toDecs bs) (toExp e)
+--
+toExp (Expr.HsIf _ a b c)                   = TH.CondE (toExp (unLoc a)) (toExp (unLoc b)) (toExp (unLoc c))
+
+-- toExp (Expr.MultiIf _ ifs)                    = TH.MultiIfE (map toGuard ifs)
+-- toExp (Expr.Case _ e alts)                    = TH.CaseE (toExp e) (map toMatch alts)
+-- toExp (Expr.Do _ ss)                          = TH.DoE (map toStmt ss)
+-- toExp e@Expr.MDo{}                            = noTH "toExp" e
+--
+toExp (Expr.ExplicitTuple _ args boxity) = ctor tupArgs
+  where
+    toTupArg (Expr.Present _ e) = Just $ unLoc e
+    toTupArg (Expr.Missing _) = Nothing
+    toTupArg _ = error "impossible case"
+
+    ctor = case boxity of
+      Boxed -> TH.TupE
+      Unboxed -> TH.UnboxedTupE
+
+    tupArgs = fmap ((fmap toExp) . toTupArg) args
+
+-- toExp (Expr.List _ xs)                        = TH.ListE (fmap toExp xs)
+toExp (Expr.HsPar _ e)
+  = TH.ParensE (toExp . unLoc $ e)
+
+toExp (Expr.SectionL _ (unLoc -> a) (unLoc -> b))
+  = TH.InfixE (Just . toExp $ a) (toExp b) Nothing
+
+toExp (Expr.SectionR _ (unLoc -> a) (unLoc -> b))
+  = TH.InfixE Nothing (toExp a) (Just . toExp $ b)
+
+toExp (Expr.RecordCon _ name HsRecFields {rec_flds})
+  = TH.RecConE (toName . unLoc $ name) (fmap toFieldExp rec_flds)
+
+toExp (Expr.RecordUpd _ (unLoc -> e) xs)                 = TH.RecUpdE (toExp e) $ case xs of
+    Left fields ->
+        let
+            f (unLoc -> x) = (name, value)
+                where
+                    value = toExp $ unLoc $ hsRecFieldArg x
+                    name =
+                        case unLoc (hsRecFieldLbl x) of
+                            Unambiguous _ (unLoc -> name) -> toName name
+                            Ambiguous _ (unLoc -> name) -> toName name
+        in
+            map f fields
+    Right xs -> error "todo"
+-- toExp (Expr.ListComp _ e ss)                  = TH.CompE $ map convert ss ++ [TH.NoBindS (toExp e)]
+--  where
+--   convert (Expr.QualStmt _ st)                = toStmt st
+--   convert s                                   = noTH "toExp ListComp" s
+-- toExp (Expr.ExpTypeSig _ e t)                 = TH.SigE (toExp e) (toType t)
+--
+toExp (Expr.ExplicitList _ (map unLoc -> args)) = TH.ListE (map toExp args)
+
+toExp (Expr.ArithSeq _ _ e)
+  = TH.ArithSeqE $ case e of
+    (From a) -> TH.FromR (toExp $ unLoc a)
+    (FromThen a b) -> TH.FromThenR (toExp $ unLoc a) (toExp $ unLoc b)
+    (FromTo a b) -> TH.FromToR (toExp $ unLoc a) (toExp $ unLoc b)
+    (FromThenTo a b c) -> TH.FromThenToR (toExp $ unLoc a) (toExp $ unLoc b) (toExp $ unLoc c)
+
+
+toExp (Expr.HsProjection _ locatedFields) =
+  let
+    extractFieldLabel (HsFieldLabel _ locatedStr) = locatedStr
+    extractFieldLabel _ = error "Don't know how to handle XHsFieldLabel constructor..."
+  in
+    TH.ProjectionE (NonEmpty.map (unpackFS . unLoc . extractFieldLabel . unLoc) locatedFields)
+
+toExp (Expr.HsGetField _ expr locatedField) =
+  let
+    extractFieldLabel (HsFieldLabel _ locatedStr) = locatedStr
+    extractFieldLabel _ = error "Don't know how to handle XHsFieldLabel constructor..."
+  in
+    TH.GetFieldE (toExp (unLoc expr)) (unpackFS . unLoc . extractFieldLabel . unLoc $ locatedField)
+
+
+toExp (Expr.HsOverLabel _ fastString) = TH.LabelE (unpackFS fastString)
+
+toExp e = todo "toExp" e
+
+
+todo :: Outputable e => String -> e -> a
+todo fun thing = error . concat $ [moduleName, ".", fun, ": not implemented: ", (showSDocUnsafe $ ppr thing)]
+
+noTH :: (HasCallStack, Show e) => String -> e -> a
+noTH fun thing = error . concat $ [moduleName, ".", fun, ": no TemplateHaskell for: ", show thing]
+
+moduleName :: String
+moduleName = "IHP.HSX.HsExpToTH"
diff --git a/IHP/HSX/Parser.hs b/IHP/HSX/Parser.hs
--- a/IHP/HSX/Parser.hs
+++ b/IHP/HSX/Parser.hs
@@ -25,16 +25,14 @@
 import Data.Void
 import qualified Data.Char as Char
 import qualified Data.Text as Text
-import Control.Monad.Fail
 import Data.String.Conversions
 import qualified Data.List as List
 import Control.Monad (unless)
-import Prelude (show)
-import qualified Language.Haskell.Meta as Haskell
-import qualified Language.Haskell.TH.Syntax as Haskell
+import qualified "template-haskell" Language.Haskell.TH.Syntax as Haskell
 import qualified "template-haskell" Language.Haskell.TH as TH
 import qualified Data.Set as Set
 import qualified Data.Containers.ListUtils as List
+import qualified IHP.HSX.HaskellParser as HaskellParser
 
 data AttributeValue = TextValue !Text | ExpressionValue !Haskell.Exp deriving (Eq, Show)
 
@@ -58,11 +56,15 @@
 -- > let position = Megaparsec.SourcePos filePath (Megaparsec.mkPos line) (Megaparsec.mkPos col)
 -- > let hsxText = "<strong>Hello</strong>"
 -- >
--- > let (Right node) = parseHsx position hsxText
-parseHsx :: SourcePos -> Text -> Either (ParseErrorBundle Text Void) Node
-parseHsx position code = runParser (setPosition position *> parser) "" code
+-- > let (Right node) = parseHsx position [] hsxText
+parseHsx :: SourcePos -> [TH.Extension] -> Text -> Either (ParseErrorBundle Text Void) Node
+parseHsx position extensions code =
+    let
+        ?extensions = extensions
+    in
+        runParser (setPosition position *> parser) "" code
 
-type Parser = Parsec Void Text
+type Parser a = (?extensions :: [TH.Extension]) => Parsec Void Text a
 
 setPosition pstateSourcePos = updateParserState (\state -> state {
         statePosState = (statePosState state) { pstateSourcePos }
@@ -76,12 +78,15 @@
     eof
     pure node
 
+hsxElement :: Parser Node
 hsxElement = try hsxComment <|> try hsxSelfClosingElement <|> hsxNormalElement
 
+manyHsxElement :: Parser Node
 manyHsxElement = do
     children <- many hsxChild
     pure (Children (stripTextNodeWhitespaces children))
 
+hsxSelfClosingElement :: Parser Node
 hsxSelfClosingElement = do
     _ <- char '<'
     name <- hsxElementName
@@ -93,6 +98,7 @@
     space
     pure (Node name attributes [] isLeaf)
 
+hsxNormalElement :: Parser Node
 hsxNormalElement = do
     (name, attributes) <- hsxOpeningElement
     let parsePreEscapedTextChildren transformText = do
@@ -117,6 +123,7 @@
             otherwise -> parseNormalHSXChildren
     pure (Node name attributes children False)
 
+hsxOpeningElement :: Parser (Text, [Attribute])
 hsxOpeningElement = do
     char '<'
     name <- hsxElementName
@@ -148,13 +155,24 @@
 
 hsxSplicedAttributes :: Parser Attribute
 hsxSplicedAttributes = do
-    name <- between (string "{...") (string "}") (takeWhile1P Nothing (\c -> c /= '}'))
+    (pos, name) <- between (string "{...") (string "}") do
+            pos <- getSourcePos
+            code <- takeWhile1P Nothing (\c -> c /= '}')
+            pure (pos, code)
     space
-    haskellExpression <- case Haskell.parseExp (cs name) of
-            Right expression -> pure (patchExpr expression)
-            Left error -> fail (show error)
+    haskellExpression <- parseHaskellExpression pos (cs name)
     pure (SpreadAttributes haskellExpression)
 
+parseHaskellExpression :: SourcePos -> Text -> Parser Haskell.Exp
+parseHaskellExpression sourcePos input = do
+    case HaskellParser.parseHaskellExpression sourcePos ?extensions (cs input) of
+        Right expression -> pure expression
+        Left (line, col, error) -> do
+            pos <- getSourcePos
+            setPosition pos { sourceLine = mkPos line, sourceColumn = mkPos col }
+            fail (show error)
+
+hsxNodeAttribute :: Parser Attribute
 hsxNodeAttribute = do
     key <- hsxAttributeName
     space
@@ -195,7 +213,7 @@
             || "hx-" `Text.isPrefixOf` name
             || name `Set.member` attributes
 
-        rawAttribute = takeWhile1P Nothing (\c -> Char.isAlphaNum c || c == '-')
+        rawAttribute = takeWhile1P Nothing (\c -> Char.isAlphaNum c || c == '-' || c == '_')
 
 
 hsxQuotedValue :: Parser AttributeValue
@@ -205,10 +223,11 @@
 
 hsxSplicedValue :: Parser AttributeValue
 hsxSplicedValue = do
-    value <- between (char '{') (char '}') (takeWhile1P Nothing (\c -> c /= '}'))
-    haskellExpression <- case Haskell.parseExp (cs value) of
-            Right expression -> pure (patchExpr expression)
-            Left error -> fail (show error)
+    (pos, value) <- between (char '{') (char '}') do
+        pos <- getSourcePos
+        code <- takeWhile1P Nothing (\c -> c /= '}')
+        pure (pos, code)
+    haskellExpression <- parseHaskellExpression pos (cs value)
     pure (ExpressionValue haskellExpression)
 
 hsxClosingElement name = (hsxClosingElement' name) <?> friendlyErrorMessage
@@ -220,6 +239,7 @@
             char ('>')
             pure ()
 
+hsxChild :: Parser Node
 hsxChild = hsxElement <|> hsxSplicedNode <|> try (space >> hsxElement) <|> hsxText
 
 -- | Parses a hsx text node
@@ -236,19 +256,20 @@
 
 hsxSplicedNode :: Parser Node
 hsxSplicedNode = do
-        expression <- doParse
-        haskellExpression <- case Haskell.parseExp (cs expression) of
-                Right expression -> pure (patchExpr expression)
-                Left error -> fail (show error)
+        (pos, expression) <- doParse
+        haskellExpression <- parseHaskellExpression pos (cs expression)
         pure (SplicedNode haskellExpression)
     where
         doParse = do
-            tree <- node
+            (pos, tree) <- node
             let value = (treeToString "" tree)
-            pure $ Text.init $ Text.tail value
+            pure (pos, Text.init $ Text.tail value)
 
-        parseTree = node <|> leaf
-        node = TokenNode <$> between (char '{') (char '}') (many parseTree)
+        parseTree = (snd <$> node) <|> leaf
+        node = between (char '{') (char '}') do
+                pos <- getSourcePos
+                tree <- many parseTree
+                pure (pos, TokenNode tree)
         leaf = TokenLeaf <$> takeWhile1P Nothing (\c -> c /= '{' && c /= '}')
         treeToString :: Text -> TokenTree -> Text
         treeToString acc (TokenLeaf value)  = acc <> value
@@ -365,7 +386,7 @@
         , "visibility", "word-spacing", "writing-mode", "is"
         , "cellspacing", "cellpadding", "bgcolor", "classes"
         , "loading"
-        , "frameborder", "allow", "allowfullscreen", "nonce", "referrerpolicy"
+        , "frameborder", "allow", "allowfullscreen", "nonce", "referrerpolicy", "slot"
         ]
 
 parents :: Set Text
@@ -593,40 +614,3 @@
         filterDuplicateSpaces' (char:rest) False | Char.isSpace char = ' ':(filterDuplicateSpaces' rest True)
         filterDuplicateSpaces' (char:rest) isRemovingSpaces = char:(filterDuplicateSpaces' rest False)
         filterDuplicateSpaces' [] isRemovingSpaces = []
-
-
-patchExpr :: TH.Exp -> TH.Exp
-patchExpr (TH.UInfixE (TH.VarE varName) (TH.VarE hash) (TH.VarE labelValue)) | hash == TH.mkName "#" = TH.AppE (TH.VarE varName) fromLabel
-    where
-            fromLabel = TH.AppTypeE (TH.VarE (TH.mkName "fromLabel")) (TH.LitT (TH.StrTyLit (show labelValue)))
---- UInfixE (UInfixE a (VarE |>) (VarE get)) (VarE #) (VarE firstName)
-patchExpr input@(TH.UInfixE (TH.UInfixE a (TH.VarE arrow) (TH.VarE get)) (TH.VarE hash) (TH.VarE labelValue)) | (hash == TH.mkName "#") && (arrow == TH.mkName "|>") && (get == TH.mkName "get") =
-        (TH.UInfixE (patchExpr a) (TH.VarE arrow) (TH.AppE (TH.VarE get) fromLabel))
-    where
-            fromLabel = TH.AppTypeE (TH.VarE (TH.mkName "fromLabel")) (TH.LitT (TH.StrTyLit (show labelValue)))
--- UInfixE (UInfixE a (VarE $) (VarE get)) (VarE #) (AppE (VarE id) (VarE checklist))
-patchExpr (TH.UInfixE (TH.UInfixE a b get) (TH.VarE hash) (TH.AppE (TH.VarE labelValue) (TH.VarE d))) | (hash == TH.mkName "#") =
-        TH.UInfixE (patchExpr a) (patchExpr b) (TH.AppE (TH.AppE get fromLabel) (TH.VarE d))
-    where
-            fromLabel = TH.AppTypeE (TH.VarE (TH.mkName "fromLabel")) (TH.LitT (TH.StrTyLit (show labelValue)))
-patchExpr (TH.UInfixE (TH.VarE varName) (TH.VarE hash) (TH.AppE (TH.VarE labelValue) arg)) | hash == TH.mkName "#" = TH.AppE (TH.AppE (TH.VarE varName) fromLabel) arg
-    where
-            fromLabel = TH.AppTypeE (TH.VarE (TH.mkName "fromLabel")) (TH.LitT (TH.StrTyLit (show labelValue)))
-patchExpr (TH.UInfixE (TH.VarE a) (TH.VarE hash) (TH.AppE (TH.VarE labelValue) (TH.VarE b))) | hash == TH.mkName "#" =
-        TH.AppE (TH.AppE (TH.VarE a) fromLabel) (TH.VarE b)
-    where
-            fromLabel = TH.AppTypeE (TH.VarE (TH.mkName "fromLabel")) (TH.LitT (TH.StrTyLit (show labelValue)))
-
-patchExpr (TH.UInfixE a b c) = TH.UInfixE (patchExpr a) (patchExpr b) (patchExpr c)
-patchExpr (TH.ParensE e) = TH.ParensE (patchExpr e)
-patchExpr (TH.RecUpdE a b) = TH.RecUpdE (patchExpr a) b
-patchExpr (TH.AppE a b) = TH.AppE (patchExpr a) (patchExpr b)
-patchExpr (TH.LamE a b) = TH.LamE a (patchExpr b)
-patchExpr (TH.LetE a b) = TH.LetE a' (patchExpr b)
-    where
-        a' = List.map patchDec a
-        patchDec (TH.ValD a (TH.NormalB b) c) = (TH.ValD a (TH.NormalB (patchExpr b)) c)
-        patchDec a = a
-patchExpr (TH.CondE a b c) = TH.CondE (patchExpr a) (patchExpr b) (patchExpr c)
-patchExpr (TH.SigE a b) = TH.SigE (patchExpr a) b
-patchExpr e = e
diff --git a/IHP/HSX/QQ.hs b/IHP/HSX/QQ.hs
--- a/IHP/HSX/QQ.hs
+++ b/IHP/HSX/QQ.hs
@@ -8,7 +8,6 @@
 module IHP.HSX.QQ (hsx) where
 
 import           Prelude
-import qualified Data.Text as Text
 import Data.Text (Text)
 import           IHP.HSX.Parser
 import qualified "template-haskell" Language.Haskell.TH           as TH
@@ -20,7 +19,6 @@
 import Text.Blaze.Internal (attribute, MarkupM (Parent, Leaf), StaticString (..))
 import Data.String.Conversions
 import IHP.HSX.ToHtml
-import Control.Monad.Fail
 import qualified Text.Megaparsec as Megaparsec
 import qualified Text.Blaze.Html.Renderer.String as BlazeString
 import qualified Data.Text as Text
@@ -38,7 +36,8 @@
 quoteHsxExpression :: String -> TH.ExpQ
 quoteHsxExpression code = do
         hsxPosition <- findHSXPosition
-        expression <- case parseHsx hsxPosition (cs code) of
+        extensions <- TH.extsEnabled
+        expression <- case parseHsx hsxPosition extensions (cs code) of
                 Left error   -> fail (Megaparsec.errorBundlePretty error)
                 Right result -> pure result
         compileToHaskell expression
diff --git a/ihp-hsx.cabal b/ihp-hsx.cabal
--- a/ihp-hsx.cabal
+++ b/ihp-hsx.cabal
@@ -1,6 +1,6 @@
 cabal-version:       2.2
 name:                ihp-hsx
-version:             0.18.0
+version:             0.20.0
 synopsis:            JSX-like but for Haskell
 description:         JSX-like templating syntax for Haskell
 license:             MIT
@@ -19,15 +19,15 @@
 library
     default-language: Haskell2010
     build-depends:
-          base               >= 4.1 && <= 4.16
+          base               >= 4.16.3 && < 4.17
         , blaze-html         >= 0.9.1 && < 0.10
-        , bytestring         >= 0.10.12 && < 0.11
-        , text               >= 1.2.4 && < 1.3
+        , bytestring         >= 0.11.3 && < 0.12
+        , template-haskell   >= 2.18.0 && < 2.19
+        , text               >= 1.2.5 && < 1.3
         , containers         >= 0.6.5 && < 0.7
-        , template-haskell   >= 2.16.0 && < 2.17
         , blaze-markup       >= 0.8.2 && < 0.9
-        , haskell-src-meta   >= 0.8.7 && < 0.9
-        , megaparsec         >= 9.0.1 && < 9.1
+        , ghc                >= 9.2.4 && < 9.3
+        , megaparsec         >= 9.2.1 && < 9.3
         , string-conversions >= 0.4.0 && < 0.5
     default-extensions:
         OverloadedStrings
@@ -62,6 +62,7 @@
         , LambdaCase
         , StandaloneDeriving
         , TemplateHaskell
+        , OverloadedRecordDot
     ghc-options:
         -fstatic-argument-transformation
         -funbox-strict-fields
@@ -80,3 +81,5 @@
         , IHP.HSX.QQ
         , IHP.HSX.ToHtml
         , IHP.HSX.ConvertibleStrings
+        , IHP.HSX.HaskellParser
+        , IHP.HSX.HsExpToTH
