diff --git a/src/libs/utils/htmldocextractor.cpp b/src/libs/utils/htmldocextractor.cpp
index 41fd38c1ee85d49d2f59d8ffdb750416ea369a8a..faf16f144317d9035afdf9cde70b71dc8da9788a 100644
--- a/src/libs/utils/htmldocextractor.cpp
+++ b/src/libs/utils/htmldocextractor.cpp
@@ -137,11 +137,32 @@ QString HtmlDocExtractor::getFunctionDescription(const QString &html,
     return contents;
 }
 
-QString HtmlDocExtractor::getQMLItemDescription(const QString &html, const QString &mark) const
+QString HtmlDocExtractor::getQmlComponentDescription(const QString &html, const QString &mark) const
 {
     return getClassOrNamespaceDescription(html, mark);
 }
 
+QString HtmlDocExtractor::getQmlPropertyDescription(const QString &html, const QString &mark) const
+{
+    QString startMark = QString("<a name=\"%1-prop\">").arg(mark);
+    int index = html.indexOf(startMark);
+    if (index == -1) {
+        startMark = QString("<a name=\"%1-signal\">").arg(mark);
+        index = html.indexOf(startMark);
+    }
+    if (index == -1)
+        return QString();
+
+    QString contents = html.mid(index + startMark.size());
+    index = contents.indexOf(QLatin1String("<p>"));
+    if (index == -1)
+        return QString();
+    contents = contents.mid(index);
+    processOutput(&contents);
+
+    return contents;
+}
+
 QString HtmlDocExtractor::getClassOrNamespaceMemberDescription(const QString &html,
                                                                const QString &startMark,
                                                                const QString &endMark) const
diff --git a/src/libs/utils/htmldocextractor.h b/src/libs/utils/htmldocextractor.h
index 8efa69b25e33eab2170088bec30ceddf2bc5b4ab..7a18cdfabe53f8a4db5c724274befc0885547288 100644
--- a/src/libs/utils/htmldocextractor.h
+++ b/src/libs/utils/htmldocextractor.h
@@ -57,7 +57,8 @@ public:
     QString getFunctionDescription(const QString &html,
                                    const QString &mark,
                                    const bool mainOverload = true) const;
-    QString getQMLItemDescription(const QString &html, const QString &mark) const;
+    QString getQmlComponentDescription(const QString &html, const QString &mark) const;
+    QString getQmlPropertyDescription(const QString &html, const QString &mark) const;
 
 private:
     QString getClassOrNamespaceMemberDescription(const QString &html,
diff --git a/src/plugins/qmljseditor/qmljshoverhandler.cpp b/src/plugins/qmljseditor/qmljshoverhandler.cpp
index 510469c39778e9d2787e2d446be294314c958d4f..3cf4e837111f9c377fe3cdef5527c16d5a3cf293 100644
--- a/src/plugins/qmljseditor/qmljshoverhandler.cpp
+++ b/src/plugins/qmljseditor/qmljshoverhandler.cpp
@@ -109,25 +109,29 @@ void HoverHandler::identifyMatch(TextEditor::ITextEditor *editor, int pos)
     if (!qmlEditor)
         return;
 
-    if (!matchDiagnosticMessage(qmlEditor, pos)) {
-        const QmlJSEditor::SemanticInfo &semanticInfo = qmlEditor->semanticInfo();
-        if (! semanticInfo.isValid() || semanticInfo.revision() != qmlEditor->editorRevision())
-            return;
-
-        QList<AST::Node *> astPath = semanticInfo.astPath(pos);
-        if (astPath.isEmpty())
-            return;
-
-        const Document::Ptr qmlDocument = semanticInfo.document;
-        LookupContext::Ptr lookupContext = semanticInfo.lookupContext(astPath);
-
-        if (!matchColorItem(lookupContext, qmlDocument, astPath, pos)) {
-            handleOrdinaryMatch(lookupContext, semanticInfo.nodeUnderCursor(pos));
-            const QString &helpId = qmlHelpId(toolTip());
-            if (!helpId.isEmpty())
-                setLastHelpItemIdentified(TextEditor::HelpItem(helpId, TextEditor::HelpItem::QML));
-        }
-    }
+    if (matchDiagnosticMessage(qmlEditor, pos))
+        return;
+
+    const QmlJSEditor::SemanticInfo &semanticInfo = qmlEditor->semanticInfo();
+    if (! semanticInfo.isValid() || semanticInfo.revision() != qmlEditor->editorRevision())
+        return;
+
+    QList<AST::Node *> astPath = semanticInfo.astPath(pos);
+    if (astPath.isEmpty())
+        return;
+
+    const Document::Ptr qmlDocument = semanticInfo.document;
+    LookupContext::Ptr lookupContext = semanticInfo.lookupContext(astPath);
+
+    if (matchColorItem(lookupContext, qmlDocument, astPath, pos))
+        return;
+
+    AST::Node *node = semanticInfo.nodeUnderCursor(pos);
+    handleOrdinaryMatch(lookupContext, node);
+
+    TextEditor::HelpItem helpItem = qmlHelpItem(lookupContext, node);
+    if (!helpItem.helpId().isEmpty())
+        setLastHelpItemIdentified(helpItem);
 }
 
 bool HoverHandler::matchDiagnosticMessage(QmlJSEditor::QmlJSTextEditor *qmlEditor, int pos)
@@ -236,19 +240,15 @@ void HoverHandler::prettyPrintTooltip(const QmlJS::Interpreter::Value *value,
         return;
 
     if (const Interpreter::ObjectValue *objectValue = value->asObjectValue()) {
-        bool found = false;
         Interpreter::PrototypeIterator iter(objectValue, context);
         while (iter.hasNext()) {
             const Interpreter::ObjectValue *prototype = iter.next();
             const QString className = prototype->className();
 
             if (! className.isEmpty()) {
-                found = !qmlHelpId(className).isEmpty();
-                if (toolTip().isEmpty() || found)
-                    setToolTip(className);
-            }
-            if (found)
+                setToolTip(className);
                 break;
+            }
         }
     } else if (const Interpreter::QmlEnumValue *enumValue =
                dynamic_cast<const Interpreter::QmlEnumValue *>(value)) {
@@ -262,10 +262,74 @@ void HoverHandler::prettyPrintTooltip(const QmlJS::Interpreter::Value *value,
     }
 }
 
-QString HoverHandler::qmlHelpId(const QString &itemName) const
+// if node refers to a property, its name and defining object are returned - otherwise zero
+static const Interpreter::ObjectValue *isMember(const LookupContext::Ptr &lookupContext,
+                                                AST::Node *node, QString *name)
 {
-    QString helpId(QLatin1String("QML.") + itemName);
-    if (!Core::HelpManager::instance()->linksForIdentifier(helpId).isEmpty())
-        return helpId;
-    return QString();
+    const Interpreter::ObjectValue *owningObject = 0;
+    if (AST::IdentifierExpression *identExp = AST::cast<AST::IdentifierExpression *>(node)) {
+        if (!identExp->name)
+            return 0;
+        *name = identExp->name->asString();
+        lookupContext->context()->lookup(*name, &owningObject);
+    } else if (AST::FieldMemberExpression *fme = AST::cast<AST::FieldMemberExpression *>(node)) {
+        if (!fme->base || !fme->name)
+            return 0;
+        *name = fme->name->asString();
+        const Interpreter::Value *base = lookupContext->evaluate(fme->base);
+        if (!base)
+            return 0;
+        owningObject = base->asObjectValue();
+        if (owningObject)
+            owningObject->lookupMember(*name, lookupContext->context(), &owningObject);
+    } else if (AST::UiQualifiedId *qid = AST::cast<AST::UiQualifiedId *>(node)) {
+        if (!qid->name)
+            return 0;
+        *name = qid->name->asString();
+        const Interpreter::Value *value = lookupContext->context()->lookup(*name, &owningObject);
+        for (AST::UiQualifiedId *it = qid->next; it; it = it->next) {
+            if (!value)
+                return 0;
+            const Interpreter::ObjectValue *next = value->asObjectValue();
+            if (!next || !it->name)
+                return 0;
+            *name = it->name->asString();
+            value = next->lookupMember(*name, lookupContext->context(), &owningObject);
+        }
+    }
+    return owningObject;
+}
+
+TextEditor::HelpItem HoverHandler::qmlHelpItem(const LookupContext::Ptr &lookupContext,
+                                               AST::Node *node) const
+{
+    QString name;
+    if (const Interpreter::ObjectValue *scope = isMember(lookupContext, node, &name)) {
+        // maybe it's a type?
+        if (!name.isEmpty() && name.at(0).isUpper()) {
+            const QString maybeHelpId(QLatin1String("QML.") + name);
+            if (!Core::HelpManager::instance()->linksForIdentifier(maybeHelpId).isEmpty())
+                return TextEditor::HelpItem(maybeHelpId, name, TextEditor::HelpItem::QmlComponent);
+        }
+
+        // otherwise, it's probably a property
+        const Interpreter::ObjectValue *lastScope;
+        scope->lookupMember(name, lookupContext->context(), &lastScope);
+        Interpreter::PrototypeIterator iter(scope, lookupContext->context());
+        while (iter.hasNext()) {
+            const Interpreter::ObjectValue *cur = iter.next();
+
+            const QString className = cur->className();
+            if (!className.isEmpty()) {
+                const QString maybeHelpId(className + QLatin1String("::") + name);
+                if (!Core::HelpManager::instance()->linksForIdentifier(maybeHelpId).isEmpty())
+                    return TextEditor::HelpItem(maybeHelpId, name, TextEditor::HelpItem::QmlProperty);
+            }
+
+            if (cur == lastScope)
+                break;
+        }
+    }
+
+    return TextEditor::HelpItem();
 }
diff --git a/src/plugins/qmljseditor/qmljshoverhandler.h b/src/plugins/qmljseditor/qmljshoverhandler.h
index ea59ccdb79f1f6ea6867ebca6b051bfe973d5eec..42af413532a770a7332f96d0da680a9a65974925 100644
--- a/src/plugins/qmljseditor/qmljshoverhandler.h
+++ b/src/plugins/qmljseditor/qmljshoverhandler.h
@@ -79,7 +79,8 @@ private:
     void prettyPrintTooltip(const QmlJS::Interpreter::Value *value,
                             const QmlJS::Interpreter::Context *context);
 
-    QString qmlHelpId(const QString &itemName) const;
+    TextEditor::HelpItem qmlHelpItem(const QmlJS::LookupContext::Ptr &lookupContext,
+                                     QmlJS::AST::Node *node) const;
 
     QmlJS::ModelManagerInterface *m_modelManager;
     QColor m_colorTip;
diff --git a/src/plugins/texteditor/helpitem.cpp b/src/plugins/texteditor/helpitem.cpp
index 33badec1c019b823c798ffd6b9378365b1094142..b22e5e3bae725e4c449f7e0c8de41dc0cd1d4f14 100644
--- a/src/plugins/texteditor/helpitem.cpp
+++ b/src/plugins/texteditor/helpitem.cpp
@@ -108,8 +108,11 @@ QString HelpItem::extractContent(bool extended) const
         case Macro:
             contents = htmlExtractor.getMacroDescription(html, m_docMark);
             break;
-        case QML:
-            contents = htmlExtractor.getQMLItemDescription(html, m_docMark);
+        case QmlComponent:
+            contents = htmlExtractor.getQmlComponentDescription(html, m_docMark);
+            break;
+        case QmlProperty:
+            contents = htmlExtractor.getQmlPropertyDescription(html, m_docMark);
             break;
 
         default:
diff --git a/src/plugins/texteditor/helpitem.h b/src/plugins/texteditor/helpitem.h
index 89f8aa7be373109cbedb0658366eb2355728128c..601f9cc27bc6824050a2f36ec93d31e110d78c3c 100644
--- a/src/plugins/texteditor/helpitem.h
+++ b/src/plugins/texteditor/helpitem.h
@@ -46,7 +46,8 @@ public:
         Macro,
         Brief,
         Function,
-        QML,
+        QmlComponent,
+        QmlProperty,
         Unknown
     };