diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,5 +1,10 @@
 # Changelog for `html-parse`
 
+## 0.2.2.0
+
+- Fix dropping of attributes in some cases (#27)
+- Fix parsing of unquoted attributes (#28)
+
 ## 0.2.1.0
 
 - Added support for decoding of character references (#18)
diff --git a/html-parse.cabal b/html-parse.cabal
--- a/html-parse.cabal
+++ b/html-parse.cabal
@@ -1,5 +1,5 @@
 name:                html-parse
-version:             0.2.1.0
+version:             0.2.2.0
 synopsis:            A high-performance HTML tokenizer
 description:
     This package provides a fast and reasonably robust HTML5 tokenizer built
@@ -52,13 +52,20 @@
 category:            Text
 build-type:          Simple
 cabal-version:       >=1.10
-tested-with:         GHC==8.4.*, GHC==8.6.*, GHC==8.8.*, GHC==8.10.*, GHC==9.0.*, GHC==9.2.*, GHC==9.4.*
+tested-with:         GHC==8.10.7,
+                     GHC==9.0.2,
+                     GHC==9.2.5,
+                     GHC==9.4.5,
+                     GHC==9.6.7,
+                     GHC==9.8.4,
+                     GHC==9.10.1,
+                     GHC==9.12.1
 extra-source-files:  changelog.md
 
 
 source-repository head
   type:                git
-  location:            git://github.com/bgamari/html-parse
+  location:            https://github.com/bgamari/html-parse
 
 library
   exposed-modules:     Text.HTML.Parser, Text.HTML.Tree
@@ -66,11 +73,11 @@
   ghc-options:         -Wall
   hs-source-dirs:      src
   other-extensions:    OverloadedStrings, DeriveGeneric
-  build-depends:       base >=4.7 && <4.20,
+  build-depends:       base >=4.7 && <4.22,
                        deepseq >=1.3 && <1.6,
                        attoparsec >=0.13 && <0.15,
                        text >=1.2 && <2.2,
-                       containers >=0.5 && <0.8
+                       containers >=0.5 && <0.9
   default-language:    Haskell2010
 
 benchmark bench
diff --git a/src/Text/HTML/Parser.hs b/src/Text/HTML/Parser.hs
--- a/src/Text/HTML/Parser.hs
+++ b/src/Text/HTML/Parser.hs
@@ -3,6 +3,9 @@
 {-# LANGUAGE LambdaCase #-}
 
 {-# OPTIONS_GHC -O2 #-}
+{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
+{-# HLINT ignore "Redundant id" #-}
+{-# HLINT ignore "Redundant bracket" #-}
 
 -- | This is a performance-oriented HTML tokenizer aim at web-crawling
 -- applications. It follows the HTML5 parsing specification quite closely,
@@ -200,6 +203,8 @@
     name <- takeWhile $ not . (isWhitespace `orC` isC '/' `orC` isC '=' `orC` isC '>')
     id $  (endOfInput >> afterAttrName tag attrs name)
       <|> (char '=' >> beforeAttrValue tag attrs name)
+      <|> (satisfy isWhitespace >> afterAttrName tag attrs name)
+      -- N.B. '/' is handled by afterAttrName
       <|> try (do mc <- peekChar
                   case mc of
                     Just c | notNameChar c ->  afterAttrName tag attrs name
@@ -211,7 +216,7 @@
 afterAttrName :: TagName -> [Attr] -> AttrName -> Parser Token
 afterAttrName tag attrs name = do
     skipWhile isWhitespace
-    id $  (char '/' >> selfClosingStartTag tag attrs)
+    id $  (char '/' >> selfClosingStartTag tag (Attr name T.empty : attrs))
       <|> (char '=' >> beforeAttrValue tag attrs name)
       <|> (char '>' >> return (TagOpen tag (Attr name T.empty : attrs)))
       <|> (endOfInput >> return endOfFileToken)
@@ -244,7 +249,7 @@
 attrValueUnquoted :: TagName -> [Attr] -> AttrName -> Parser Token
 attrValueUnquoted tag attrs name = do
     value <- takeTill $ isWhitespace `orC` isC '>'
-    id $  (satisfy isWhitespace >> beforeAttrName tag attrs) -- unsure: don't emit?
+    id $  (satisfy isWhitespace >> beforeAttrName tag (Attr name value : attrs))
       <|> (char '>' >> return (TagOpen tag (Attr name value : attrs)))
       <|> (endOfInput >> return endOfFileToken)
 
diff --git a/tests/Text/HTML/ParserSpec.hs b/tests/Text/HTML/ParserSpec.hs
--- a/tests/Text/HTML/ParserSpec.hs
+++ b/tests/Text/HTML/ParserSpec.hs
@@ -85,6 +85,10 @@
 maxListOf :: Int -> Gen a -> Gen [a]
 maxListOf n g = take n <$> listOf g
 
+parsesTo :: String -> [Token] -> Spec
+parsesTo str expected = do
+    it ("parses " <> str) $ do
+        parseTokens (T.pack str) `shouldBe` expected
 
 spec :: Spec
 spec = do
@@ -110,3 +114,16 @@
         parseTokens "<!-- img src=\"/www_images/NCEP_GFS.gif\"><!- -------------------------------------------------------- >" `shouldBe` [Comment " img src=\"/www_images/NCEP_GFS.gif\"><!- -------------------------------------------------------- >"]
       it "parses entity" $ do
         parseTokens "&lt;" `shouldBe` [ContentText "<"]
+      -- traling whitespace after attributes
+      it "<foo .baz .bar>" $ do
+        parseTokens "<foo .baz .bar>" `shouldBe` [TagOpen "foo" [Attr ".bar" "", Attr ".baz" ""]]
+      it "<foo .baz .bar >" $ do
+        parseTokens "<foo .baz .bar >" `shouldBe` [TagOpen "foo" [Attr ".bar" "", Attr ".baz" ""]]
+      -- traling whitespace after attributes in self-closing tag (#27)
+      "<foo .baz .bar/>" `parsesTo` [TagSelfClose "foo" [Attr ".bar" "", Attr ".baz" ""]]
+      "<foo .baz .bar />" `parsesTo` [TagSelfClose "foo" [Attr ".bar" "", Attr ".baz" ""]]
+      -- #28
+      "<foo bar=\"baz\" foo='qux' a=b>" `parsesTo` [TagOpen "foo" [Attr "a" "b", Attr "foo" "qux", Attr "bar" "baz"]]
+      "<foo bar=baz foo=qux a=b >" `parsesTo` [TagOpen "foo" [Attr "a" "b", Attr "foo" "qux", Attr "bar" "baz"]]
+      "<foo bar=baz >" `parsesTo` [TagOpen "foo" [Attr "bar" "baz"]]
+      "<foo bar=baz>" `parsesTo` [TagOpen "foo" [Attr "bar" "baz"]]
