diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5c0f5148..31fc43d1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,12 +1,16 @@
 # Changelog
 
-# 4.3.1-SNAPSHOT
+# $nap;
 * Fix DexGuard optimization issue ([#216])
Thanks [@francescocervone]
 * module `images`: `GifSupport` and `SvgSupport` use `Class.forName` instead access to full qualified class name
+* `ext-table`: fix links in tables ([#224])
+* `ext-table`: proper borders (equal for all sides)
 
 [#216]: https://github.com/noties/Markwon/pull/216
+[#224]: https://github.com/noties/Markwon/issues/224
 [@francescocervone]: https://github.com/francescocervone
 
+
 # 4.3.0
 * add `MarkwonInlineParserPlugin` in `inline-parser` module
 * `JLatexMathPlugin` now supports inline LaTeX structures via `MarkwonInlineParserPlugin` 
diff --git a/app/src/debug/java/io/noties/markwon/debug/ColorBlendView.java b/app/src/debug/java/io/noties/markwon/debug/ColorBlendView.java
new file mode 100644
index 00000000..baf5e92b
--- /dev/null
+++ b/app/src/debug/java/io/noties/markwon/debug/ColorBlendView.java
@@ -0,0 +1,59 @@
+package io.noties.markwon.debug;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.View;
+
+import androidx.annotation.Nullable;
+
+import io.noties.markwon.app.R;
+import io.noties.markwon.utils.ColorUtils;
+
+public class ColorBlendView extends View {
+
+    private final Rect rect = new Rect();
+    private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+
+    private int background;
+    private int foreground;
+
+    public ColorBlendView(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+
+        if (attrs != null) {
+            final TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ColorBlendView);
+            try {
+                background = array.getColor(R.styleable.ColorBlendView_cbv_background, 0);
+                foreground = array.getColor(R.styleable.ColorBlendView_cbv_foreground, 0);
+            } finally {
+                array.recycle();
+            }
+        }
+
+        paint.setStyle(Paint.Style.FILL);
+
+        setWillNotDraw(false);
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+
+        final int side = getWidth() / 11;
+
+        rect.set(0, 0, side, getHeight());
+
+        canvas.translate(getPaddingLeft(), 0F);
+
+        for (int i = 0; i < 11; i++) {
+            final float alpha = i / 10F;
+            paint.setColor(ColorUtils.blend(foreground, background, alpha));
+            canvas.drawRect(rect, paint);
+            canvas.translate(side, 0F);
+        }
+    }
+}
diff --git a/app/src/debug/res/layout/debug_color_blend.xml b/app/src/debug/res/layout/debug_color_blend.xml
new file mode 100644
index 00000000..cacc73fa
--- /dev/null
+++ b/app/src/debug/res/layout/debug_color_blend.xml
@@ -0,0 +1,34 @@
+
+
+
+    
+
+    
+
+    
+
+    
+
+
+
\ No newline at end of file
diff --git a/app/src/debug/res/values/attrs.xml b/app/src/debug/res/values/attrs.xml
index 161f7806..0636e107 100644
--- a/app/src/debug/res/values/attrs.xml
+++ b/app/src/debug/res/values/attrs.xml
@@ -8,4 +8,9 @@
         
     
 
+    
+        
+        
+    
+
 
\ No newline at end of file
diff --git a/markwon-core/src/main/java/io/noties/markwon/utils/ColorUtils.java b/markwon-core/src/main/java/io/noties/markwon/utils/ColorUtils.java
index d2a8bc6e..d5d9703d 100644
--- a/markwon-core/src/main/java/io/noties/markwon/utils/ColorUtils.java
+++ b/markwon-core/src/main/java/io/noties/markwon/utils/ColorUtils.java
@@ -1,11 +1,33 @@
 package io.noties.markwon.utils;
 
+import android.graphics.Color;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.FloatRange;
+import androidx.annotation.IntRange;
+
 public abstract class ColorUtils {
 
-    public static int applyAlpha(int color, int alpha) {
+    @ColorInt
+    public static int applyAlpha(
+            @ColorInt int color,
+            @IntRange(from = 0, to = 255) int alpha) {
         return (color & 0x00FFFFFF) | (alpha << 24);
     }
 
+    // blend two colors w/ specified ratio, resulting color won't have alpha channel
+    @ColorInt
+    public static int blend(
+            @ColorInt int foreground,
+            @ColorInt int background,
+            @FloatRange(from = 0.0F, to = 1.0F) float ratio) {
+        return Color.rgb(
+                (int) (((1F - ratio) * Color.red(foreground)) + (ratio * Color.red(background))),
+                (int) (((1F - ratio) * Color.green(foreground)) + (ratio * Color.green(background))),
+                (int) (((1F - ratio) * Color.blue(foreground)) + (ratio * Color.blue(background)))
+        );
+    }
+
     private ColorUtils() {
     }
 }
diff --git a/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TablePlugin.java b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TablePlugin.java
index 93dccd83..8e624e01 100644
--- a/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TablePlugin.java
+++ b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TablePlugin.java
@@ -123,8 +123,13 @@ public class TablePlugin extends AbstractMarkwonPlugin {
 
                             visitor.blockStart(tableBlock);
 
+                            final int length = visitor.length();
+
                             visitor.visitChildren(tableBlock);
 
+                            // @since $nap; apply table span for the full table
+                            visitor.setSpans(length, new TableSpan());
+
                             visitor.blockEnd(tableBlock);
                         }
                     })
diff --git a/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableRowSpan.java b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableRowSpan.java
index a90818fb..f6653cf8 100644
--- a/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableRowSpan.java
+++ b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableRowSpan.java
@@ -5,6 +5,7 @@ import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.text.Layout;
+import android.text.Spanned;
 import android.text.StaticLayout;
 import android.text.TextPaint;
 import android.text.style.ReplacementSpan;
@@ -19,6 +20,8 @@ import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.List;
 
+import io.noties.markwon.utils.LeadingMarginUtils;
+
 public class TableRowSpan extends ReplacementSpan {
 
     public static final int ALIGN_LEFT = 0;
@@ -139,16 +142,16 @@ public class TableRowSpan extends ReplacementSpan {
             int top,
             int y,
             int bottom,
-            @NonNull Paint paint) {
+            @NonNull Paint p) {
 
         if (recreateLayouts(canvas.getWidth())) {
             width = canvas.getWidth();
             // @since $nap; it's important to cast to TextPaint in order to display links, etc
-            if (paint instanceof TextPaint) {
+            if (p instanceof TextPaint) {
                 // there must be a reason why this method receives Paint instead of TextPaint...
-                textPaint.set((TextPaint) paint);
+                textPaint.set((TextPaint) p);
             } else {
-                textPaint.set(paint);
+                textPaint.set(p);
             }
             makeNewLayouts();
         }
@@ -161,28 +164,25 @@ public class TableRowSpan extends ReplacementSpan {
 
         final int w = width / size;
 
-        // feels like magic...
-        final int heightDiff = (bottom - top - height) / 4;
-
         // @since 1.1.1
         // draw backgrounds
         {
             if (header) {
-                theme.applyTableHeaderRowStyle(this.paint);
+                theme.applyTableHeaderRowStyle(paint);
             } else if (odd) {
-                theme.applyTableOddRowStyle(this.paint);
+                theme.applyTableOddRowStyle(paint);
             } else {
                 // even
-                theme.applyTableEvenRowStyle(this.paint);
+                theme.applyTableEvenRowStyle(paint);
             }
 
             // if present (0 is transparent)
-            if (this.paint.getColor() != 0) {
+            if (paint.getColor() != 0) {
                 final int save = canvas.save();
                 try {
                     rect.set(0, 0, width, bottom - top);
-                    canvas.translate(x, top - heightDiff);
-                    canvas.drawRect(rect, this.paint);
+                    canvas.translate(x, top);
+                    canvas.drawRect(rect, paint);
                 } finally {
                     canvas.restoreToCount(save);
                 }
@@ -192,25 +192,73 @@ public class TableRowSpan extends ReplacementSpan {
         // @since 1.1.1 reset after applying background color
         // as background changes color attribute and if not specific tableBorderColor
         // is specified then after this row all borders will have color of this row (plus alpha)
-        this.paint.set(paint);
-        theme.applyTableBorderStyle(this.paint);
+        paint.set(p);
+        theme.applyTableBorderStyle(paint);
 
         final int borderWidth = theme.tableBorderWidth(paint);
         final boolean drawBorder = borderWidth > 0;
+
+        // why divided by 4 gives a more or less good result is still not clear (shouldn't it be 2?)
+        final int heightDiff = (bottom - top - height) / 4;
+
+        // required for borderTop calculation
+        final boolean isFirstTableRow;
+
+        // @since $nap;
         if (drawBorder) {
-            rect.set(0, 0, w, bottom - top);
+            boolean first = false;
+            // only if first draw the line
+            {
+                final Spanned spanned = (Spanned) text;
+                final TableSpan[] spans = spanned.getSpans(start, end, TableSpan.class);
+                if (spans != null && spans.length > 0) {
+                    final TableSpan span = spans[0];
+                    if (LeadingMarginUtils.selfStart(start, text, span)) {
+                        first = true;
+                        rect.set((int) x, top, width, top + borderWidth);
+                        canvas.drawRect(rect, paint);
+                    }
+                }
+            }
+
+            // draw the line at the bottom
+            rect.set((int) x, bottom - borderWidth, width, bottom);
+            canvas.drawRect(rect, paint);
+
+            isFirstTableRow = first;
+        } else {
+            isFirstTableRow = false;
         }
 
+        final int borderWidthHalf = borderWidth / 2;
+
+        // to NOT overlap borders inset top and bottom
+        final int borderTop = isFirstTableRow ? borderWidth : 0;
+        final int borderBottom = bottom - top - borderWidth;
+
         StaticLayout layout;
         for (int i = 0; i < size; i++) {
             layout = layouts.get(i);
             final int save = canvas.save();
             try {
 
-                canvas.translate(x + (i * w), top - heightDiff);
+                canvas.translate(x + (i * w), top);
 
+                // @since $nap;
                 if (drawBorder) {
-                    canvas.drawRect(rect, this.paint);
+                    // first vertical border will have full width (it cannot exceed canvas)
+                    if (i == 0) {
+                        rect.set(0, borderTop, borderWidth, borderBottom);
+                    } else {
+                        rect.set(-borderWidthHalf, borderTop, borderWidthHalf, borderBottom);
+                    }
+
+                    canvas.drawRect(rect, paint);
+
+                    if (i == (size - 1)) {
+                        rect.set(w - borderWidth, borderTop, w, borderBottom);
+                        canvas.drawRect(rect, paint);
+                    }
                 }
 
                 canvas.translate(padding, padding + heightDiff);
diff --git a/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableSpan.java b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableSpan.java
new file mode 100644
index 00000000..bba40d76
--- /dev/null
+++ b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableSpan.java
@@ -0,0 +1,7 @@
+package io.noties.markwon.ext.tables;
+
+/**
+ * @since $nap;
+ */
+public class TableSpan {
+}
diff --git a/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableTheme.java b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableTheme.java
index f4a1c5cc..48655220 100644
--- a/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableTheme.java
+++ b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableTheme.java
@@ -10,6 +10,7 @@ import androidx.annotation.Px;
 import io.noties.markwon.utils.ColorUtils;
 import io.noties.markwon.utils.Dip;
 
+@SuppressWarnings("WeakerAccess")
 public class TableTheme {
 
     @NonNull
@@ -101,7 +102,8 @@ public class TableTheme {
         }
 
         paint.setColor(color);
-        paint.setStyle(Paint.Style.STROKE);
+        // @since $nap; before it was STROKE... change to FILL as we draw border differently
+        paint.setStyle(Paint.Style.FILL);
     }
 
     public void applyTableOddRowStyle(@NonNull Paint paint) {
diff --git a/sample/src/main/java/io/noties/markwon/sample/table/TableActivity.java b/sample/src/main/java/io/noties/markwon/sample/table/TableActivity.java
index a47a13e2..d7153ec6 100644
--- a/sample/src/main/java/io/noties/markwon/sample/table/TableActivity.java
+++ b/sample/src/main/java/io/noties/markwon/sample/table/TableActivity.java
@@ -1,17 +1,22 @@
 package io.noties.markwon.sample.table;
 
+import android.graphics.Color;
 import android.os.Bundle;
 import android.widget.TextView;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import io.noties.debug.Debug;
 import io.noties.markwon.Markwon;
 import io.noties.markwon.ext.tables.TablePlugin;
+import io.noties.markwon.ext.tables.TableTheme;
 import io.noties.markwon.linkify.LinkifyPlugin;
 import io.noties.markwon.sample.ActivityWithMenuOptions;
 import io.noties.markwon.sample.MenuOptions;
 import io.noties.markwon.sample.R;
+import io.noties.markwon.utils.ColorUtils;
+import io.noties.markwon.utils.Dip;
 
 public class TableActivity extends ActivityWithMenuOptions {
 
@@ -19,6 +24,7 @@ public class TableActivity extends ActivityWithMenuOptions {
     @Override
     public MenuOptions menuOptions() {
         return MenuOptions.create()
+                .add("customize", this::customize)
                 .add("tableAndLinkify", this::tableAndLinkify);
     }
 
@@ -33,6 +39,32 @@ public class TableActivity extends ActivityWithMenuOptions {
         tableAndLinkify();
     }
 
+    private void customize() {
+        final String md = "" +
+                "| HEADER | HEADER | HEADER |\n" +
+                "|:----:|:----:|:----:|\n" +
+                "|   测试  |   测试   |   测试   |\n" +
+                "|  测试  |   测试   |  测测测12345试测试测试   |\n" +
+                "|   测试  |   测试   |   123445   |\n" +
+                "|   测试  |   测试   |   (650) 555-1212   |\n" +
+                "|   测试  |   测试   |   [link](#)   |\n";
+
+        final Markwon markwon = Markwon.builder(this)
+                .usePlugin(TablePlugin.create(builder -> {
+                    final Dip dip = Dip.create(this);
+                    builder
+                            .tableBorderWidth(dip.toPx(2))
+                            .tableBorderColor(Color.YELLOW)
+                            .tableCellPadding(dip.toPx(4))
+                            .tableHeaderRowBackgroundColor(ColorUtils.applyAlpha(Color.RED, 80))
+                            .tableEvenRowBackgroundColor(ColorUtils.applyAlpha(Color.GREEN, 80))
+                            .tableOddRowBackgroundColor(ColorUtils.applyAlpha(Color.BLUE, 80));
+                }))
+                .build();
+
+        markwon.setMarkdown(textView, md);
+    }
+
     private void tableAndLinkify() {
         final String md = "" +
                 "| HEADER | HEADER | HEADER |\n" +
@@ -45,7 +77,7 @@ public class TableActivity extends ActivityWithMenuOptions {
                 "\n" +
                 "测试\n" +
                 "\n" +
-                "[https://www.baidu.com](https://www.baidu.com)";
+                "[link link](https://link.link)";
 
         final Markwon markwon = Markwon.builder(this)
                 .usePlugin(LinkifyPlugin.create())