diff --git a/frontend/src/components/AbsoluteContainer.jsx b/frontend/src/components/AbsoluteContainer.jsx
deleted file mode 100644
index b089af83826547492054ce95d69e270257d70bc1..0000000000000000000000000000000000000000
--- a/frontend/src/components/AbsoluteContainer.jsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import React, { Component, PropTypes } from "react";
-
-export default ComposedComponent => class extends Component {
-    static displayName = "AbsoluteContainer["+(ComposedComponent.displayName || ComposedComponent.name)+"]";
-
-    render() {
-        const { className, style, width, height } = this.props;
-        return (
-            <div className={className} style={{ position: "relative", ...style }}>
-                <div style={{ position: "absolute", top: 0, left: 0, width: width, height: height }}>
-                { width != null && height != null &&
-                    <ComposedComponent
-                        width={width}
-                        height={height}
-                        {...this.props}
-                    />
-                }
-                </div>
-            </div>
-        );
-    }
-}
diff --git a/frontend/src/dashboard/components/DashCard.jsx b/frontend/src/dashboard/components/DashCard.jsx
index ba77ea073ac762db4f3f44467262f95755ec71ac..9a6ee29f23f65be659402dc042d6875ca1d5a682 100644
--- a/frontend/src/dashboard/components/DashCard.jsx
+++ b/frontend/src/dashboard/components/DashCard.jsx
@@ -4,8 +4,6 @@ import ReactDOM from "react-dom";
 import visualizations from "metabase/visualizations";
 
 import Visualization from "metabase/visualizations/components/Visualization.jsx";
-import LegendHeader from "metabase/visualizations/components/LegendHeader.jsx";
-import LoadingSpinner from "metabase/components/LoadingSpinner.jsx";
 
 import Icon from "metabase/components/Icon.jsx";
 
@@ -74,8 +72,9 @@ export default class DashCard extends Component {
         }
     }
 
-    renderCard(CardVisualization) {
+    render() {
         const { dashcard, cardData, isEditing, onAddSeries, onRemove } = this.props;
+
         const cards = [dashcard.card].concat(dashcard.series || []);
         const series = cards
             .map(card => ({
@@ -86,28 +85,25 @@ export default class DashCard extends Component {
         const errors = series.map(s => s.error).filter(e => e);
         const error = errors[0] || this.state.error;
 
+        let errorMessage;
         if (error) {
-            let message;
             if (error.data) {
-                message = error.data.message;
+                errorMessage = error.data.message;
             } else if (error.status === 503) {
-                message = "I'm sorry, the server timed out while asking your question."
+                errorMessage = "I'm sorry, the server timed out while asking your question."
             } else if (typeof error === "string") {
-                message = error;
+                errorMessage = error;
             } else {
-                message = "Oh snap!  Something went wrong loading this card :sad:";
+                errorMessage = "Oh snap!  Something went wrong loading this card :sad:";
             }
-            return (
-                <div className="p1 text-centered flex-full flex flex-column layout-centered">
-                    <h2 className="text-normal text-grey-2">{message}</h2>
-                </div>
-            );
         }
 
-        if (series.length > 0 && _.every(series, (s) => s.data)) {
-            return (
+        const CardVisualization = visualizations.get(series[0].card.display);
+        return (
+            <div className={"Card bordered rounded flex flex-column " + cx({ "Card--recent": dashcard.isAdded })}>
                 <Visualization
                     className="flex-full"
+                    error={errorMessage}
                     series={series}
                     isDashboard={true}
                     isEditing={isEditing}
@@ -115,32 +111,6 @@ export default class DashCard extends Component {
                     actionButtons={isEditing ? <DashCardActionButtons series={series} visualization={CardVisualization} onRemove={onRemove} onAddSeries={onAddSeries} /> : undefined}
                     onUpdateVisualizationSetting={this.props.onUpdateVisualizationSetting}
                 />
-            );
-        }
-
-        return (
-            <div className="p1 text-brand text-centered flex-full flex flex-column layout-centered">
-                <LoadingSpinner />
-                <h1 className="ml1 text-normal text-grey-2">Loading...</h1>
-            </div>
-        );
-    }
-
-    render() {
-        const { dashcard, onAddSeries, onRemove, isEditing } = this.props;
-        const series = [dashcard.card].concat(dashcard.series || []).map(card => ({ card }));
-        const Viz = visualizations.get(series[0].card.display);
-        return (
-            <div className={"Card bordered rounded flex flex-column " + cx({ "Card--recent": dashcard.isAdded })}>
-                { !Viz.noHeader &&
-                    <div className="p1">
-                        <LegendHeader
-                            series={series}
-                            actionButtons={isEditing ? <DashCardActionButtons visualization={Viz} series={series} onRemove={onRemove} onAddSeries={onAddSeries} /> : undefined}
-                        />
-                    </div>
-                }
-                {this.renderCard(Viz)}
             </div>
         );
     }
diff --git a/frontend/src/visualizations/components/CardRenderer.jsx b/frontend/src/visualizations/components/CardRenderer.jsx
index eec202f5357748567497218e70688d7750b30999..c7a007cdc71fa45b252fffef21f0470689293a0c 100644
--- a/frontend/src/visualizations/components/CardRenderer.jsx
+++ b/frontend/src/visualizations/components/CardRenderer.jsx
@@ -2,7 +2,6 @@ import React, { Component, PropTypes } from "react";
 import ReactDOM from "react-dom";
 
 import ExplicitSize from "metabase/components/ExplicitSize.jsx";
-import AbsoluteContainer from "metabase/components/AbsoluteContainer.jsx";
 
 import * as charting from "metabase/visualizations/lib/CardRenderer";
 
@@ -10,9 +9,9 @@ import { isSameSeries } from "metabase/visualizations/lib/utils";
 import { getSettingsForVisualization } from "metabase/lib/visualization_settings";
 
 import dc from "dc";
+import cx from "classnames";
 
 @ExplicitSize
-@AbsoluteContainer
 export default class CardRenderer extends Component {
     static propTypes = {
         chartType: PropTypes.string.isRequired,
@@ -27,8 +26,7 @@ export default class CardRenderer extends Component {
     }
 
     componentDidMount() {
-        // avoid race condition with initial layout
-        setTimeout(() => this.renderChart());
+        this.renderChart();
     }
 
     componentDidUpdate() {
@@ -55,7 +53,11 @@ export default class CardRenderer extends Component {
 
         // reset the DOM:
         let element = parent.firstChild;
-        parent.removeChild(element);
+        if (element) {
+            parent.removeChild(element);
+        }
+
+        // create a new container element
         element = document.createElement("div");
         parent.appendChild(element);
 
@@ -80,9 +82,7 @@ export default class CardRenderer extends Component {
 
     render() {
         return (
-            <div className="Card-outer">
-                <div ref="chart"></div>
-            </div>
+            <div className={cx(this.props.className, "Card-outer")}></div>
         );
     }
 }
diff --git a/frontend/src/visualizations/components/Legend.css b/frontend/src/visualizations/components/Legend.css
index e2c2f1be89e3f476368560cd53cdf5f4735170e9..fa82edb740ab76933401d6d1abdea075e3c74997 100644
--- a/frontend/src/visualizations/components/Legend.css
+++ b/frontend/src/visualizations/components/Legend.css
@@ -13,7 +13,6 @@ fullscreen dashboard mode
 :local .LegendHeader {
   margin-top: 0.5em;
   margin-bottom: 0.5em;
-  height: 24px;
 }
 
 :local(.LegendItem).muted {
diff --git a/frontend/src/visualizations/components/Visualization.jsx b/frontend/src/visualizations/components/Visualization.jsx
index cca5d898f809a53d826631ef5d6b7273c859f398..f7a9cd733225038919377ad1b665af4569b657ca 100644
--- a/frontend/src/visualizations/components/Visualization.jsx
+++ b/frontend/src/visualizations/components/Visualization.jsx
@@ -1,10 +1,20 @@
 import React, { Component, PropTypes } from "react";
 
+import ExplicitSize from "metabase/components/ExplicitSize.jsx";
+import LegendHeader from "metabase/visualizations/components/LegendHeader.jsx";
+import LoadingSpinner from "metabase/components/LoadingSpinner.jsx";
+import Icon from "metabase/components/Icon.jsx";
+import Tooltip from "metabase/components/Tooltip.jsx";
+
 import visualizations from "metabase/visualizations";
 
 import i from "icepick";
 import _ from "underscore";
+import cx from "classnames";
+
+const ERROR_MESSAGE_GENERIC = "There was a problem displaying this chart.";
 
+@ExplicitSize
 export default class Visualization extends Component {
     constructor(props, context) {
         super(props, context)
@@ -36,29 +46,6 @@ export default class Visualization extends Component {
         onUpdateVisualizationSetting: (...args) => console.warn("onUpdateVisualizationSetting", args)
     };
 
-    componentWillMount() {
-        this.componentWillReceiveProps(this.props);
-    }
-
-    componentWillReceiveProps(newProps) {
-        let { card, data } = newProps.series[0]
-        if (!data) {
-            this.setState({ error: "No data (TODO)" });
-        } else if (!card.display) {
-            this.setState({ error: "Chart type not set" });
-        } else {
-            let CardVisualization = visualizations.get(card.display);
-            try {
-                if (CardVisualization.checkRenderable) {
-                    CardVisualization.checkRenderable(data.cols, data.rows);
-                }
-                this.setState({ error: null });
-            } catch (e) {
-                this.setState({ error: e.message || "Missing error message (TODO)" });
-            }
-        }
-    }
-
     onHoverChange(hovered) {
         const { renderInfo } = this.state;
         if (hovered) {
@@ -80,33 +67,72 @@ export default class Visualization extends Component {
     }
 
     render() {
+        const { series, actionButtons, className, isDashboard, width } = this.props;
+        const CardVisualization = visualizations.get(series[0].card.display);
+        const small = width < 330;
+
         let error = this.props.error || this.state.error;
-        if (error) {
-            return (
-                <div className="QueryError flex full align-center text-error">
-                    <div className="QueryError-iconWrapper">
-                        <svg className="QueryError-icon" viewBox="0 0 32 32" width="64" height="64" fill="currentcolor">
-                            <path d="M4 8 L8 4 L16 12 L24 4 L28 8 L20 16 L28 24 L24 28 L16 20 L8 28 L4 24 L12 16 z "></path>
-                        </svg>
-                    </div>
-                    <span className="QueryError-message">{error}</span>
-                </div>
-            );
-        } else {
-            let { series } = this.props;
-            let CardVisualization = visualizations.get(series[0].card.display);
-            return (
-                <CardVisualization
-                    {...this.props}
-                    series={series}
-                    card={series[0].card} // convienence for single-series visualizations
-                    data={series[0].data} // convienence for single-series visualizations
-                    hovered={this.state.hovered}
-                    onHoverChange={this.onHoverChange}
-                    onRenderError={this.onRenderError}
-                    onRender={this.onRender}
-                />
-            );
+        let loading = !(series.length > 0 && _.every(series, (s) => s.data));
+
+        if (!loading && !error) {
+            if (!CardVisualization) {
+                error = "Could not find visualization";
+            } else {
+                try {
+                    if (CardVisualization.checkRenderable) {
+                        CardVisualization.checkRenderable(series[0].data.cols, series[0].data.rows);
+                    }
+                } catch (e) {
+                    error = e.message || "Could not display this chart with this data.";
+                }
+            }
         }
+
+        return (
+            <div className={cx(className, "flex flex-column")}>
+                { isDashboard && (loading || error || !CardVisualization.noHeader) ?
+                    <div className="p1 flex-no-shrink">
+                        <LegendHeader
+                            series={series}
+                            actionButtons={actionButtons}
+                        />
+                    </div>
+                : null
+                }
+                { error ?
+                    <div className="flex-full px1 pb1 text-centered text-slate-light flex flex-column layout-centered">
+                        <Tooltip tooltip={isDashboard ? ERROR_MESSAGE_GENERIC : error} isEnabled={small}>
+                            <div className="mb2">
+                                <Icon name="warning" width={50} height={50} />
+                            </div>
+                        </Tooltip>
+                        { !small &&
+                            <span className="h4 text-bold">
+                                { isDashboard ? ERROR_MESSAGE_GENERIC : error }
+                            </span>
+                        }
+                    </div>
+                : loading ?
+                    <div className="flex-full p1 text-centered text-brand flex flex-column layout-centered">
+                        <LoadingSpinner />
+                        <span className="h4 text-bold ml1 text-slate-light">
+                            Loading...
+                        </span>
+                    </div>
+                :
+                    <CardVisualization
+                        {...this.props}
+                        className="flex-full"
+                        series={series}
+                        card={series[0].card} // convienence for single-series visualizations
+                        data={series[0].data} // convienence for single-series visualizations
+                        hovered={this.state.hovered}
+                        onHoverChange={this.onHoverChange}
+                        onRenderError={this.onRenderError}
+                        onRender={this.onRender}
+                    />
+                }
+            </div>
+        );
     }
 }