diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo
index 5ea8610..34d4e86 100644
--- a/Doc/Zsh/expn.yo
+++ b/Doc/Zsh/expn.yo
@@ -1335,6 +1335,13 @@ will remove the same matches as for `tt(#)', but in reverse order, and the
 form using `tt(%%)' will remove the same matches as for `tt(##)' in reverse
 order.
 )
+item(tt(x:)var(width)tt(:))(
+Index-post-width: for strings substitutes index of first character that is
+located fully after width var(width) of characters (multibyte characters may
+have widths of e.g. 2, see the tt(m) flag). For arrays it substitutes index of
+first element that appears after elements whose summed width is at least
+var(width). -1 is substituted if there is no such character or array element.
+)
 item(tt(B))(
 Include the index of the beginning of the match in the result.
 )
diff --git a/Src/subst.c b/Src/subst.c
index 021d234..764bd17 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -1590,6 +1590,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags)
     int flags = 0;
     /* Value from (I) flag, used for ditto. */
     int flnum = 0;
+    /* Value from (y) flag. */
+    int ynum = -1;
     /*
      * sortit is to be passed to strmetasort().
      * indord is the (a) flag, which for consistency doesn't get
@@ -1901,6 +1903,14 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags)
 		    whichlen = 3;
 		    break;
 
+		case 'y':
+		    s++;
+		    ynum = get_intarg(&s, &dellen);
+		    if (ynum < 0)
+			goto flagerr;
+		    s--;
+		    break;
+
 		case 'f':
 		    spsep = "\n";
 		    break;
@@ -3342,6 +3352,51 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags)
 	val = dupstring(buf);
 	isarr = 0;
     }
+
+    /* Index-post-width */
+    if(ynum >= 0) {
+        char buf[14];
+
+	if (isarr) {
+            long index;
+
+            // Width 0 is treated immedietally – any
+            // first array element fulfils
+            if ( ynum == 0 ) {
+                if( *aval )
+                    index = 1;
+                else
+                    index = -1;
+            } else {
+                char **ctr = aval;
+                long count = 0, current_width = 0;
+                index = -1;
+
+                while( *ctr ) {
+                    count ++;
+                    current_width += MB_METASTRLEN2(*ctr, 1);
+
+                    if( current_width >= ynum ) {
+                        // Element after the required width
+                        if( *(ctr+1) )
+                            index = count+1;
+                        else
+                            index = -1;
+                        break;
+                    }
+
+                    ctr ++;
+                }
+            }
+
+            sprintf(buf, "%ld", index);
+        } else {
+            sprintf(buf, "%d", mb_index_post_width(val, ynum));
+        }
+        val = dupstring(buf);
+        isarr = 0;
+    }
+
     /* At this point we make sure that our arrayness has affected the
      * arrayness of the linked list.  Then, we can turn our value into
      * a scalar for convenience sake without affecting the arrayness
diff --git a/Src/utils.c b/Src/utils.c
index 0afa8c9..310b0db 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -5154,6 +5154,104 @@ mb_charlenconv(const char *s, int slen, wint_t *wcp)
     return mb_charlenconv_r(s, slen, wcp, &mb_shiftstate);
 }
 
+/*
+ * Returns index of character that is located first after width `width`
+ */
+/**/
+mod_export int
+mb_index_post_width(char *ptr, int width)
+{
+    char inchar, *laststart;
+    size_t ret;
+    wchar_t wc;
+    int num, num_in_char, index;
+
+    // All characters treated as width 1
+    if (!isset(MULTIBYTE)) {
+        size_t len = ztrlen(ptr);
+        if( len > width ) {
+            return width + 1;
+        } else {
+            return -1;
+        }
+    }
+
+    // Width 0 is treated immedietally
+    if( width == 0 ) {
+        if( *ptr )
+            return 1;
+        else
+            return -1;
+    }
+
+    laststart = ptr;
+    ret = MB_INVALID;
+    num = num_in_char = index = 0;
+
+    memset(&mb_shiftstate, 0, sizeof(mb_shiftstate));
+    while (*ptr) {
+	if (*ptr == Meta)
+	    inchar = *++ptr ^ 32;
+	else
+	    inchar = *ptr;
+	ptr++;
+	ret = mbrtowc(&wc, &inchar, 1, &mb_shiftstate);
+
+	if (ret == MB_INCOMPLETE) {
+	    num_in_char++;
+	} else {
+            /* Count complete chars, which basically should be indexes in
+             * wchar_t array, right? */
+            index++;
+
+	    if (ret == MB_INVALID) {
+		/* Reset, treat as single character, and single width */
+		memset(&mb_shiftstate, 0, sizeof(mb_shiftstate));
+		ptr = laststart + (*laststart == Meta) + 1;
+		num++;
+	    } else {
+		/*
+		 * Returns -1 if not a printable character.  We
+		 * turn this into 0. That makes quite sense as
+                 * we are interested in width of characters,
+                 * and an unprintable one doesn't have it
+		 */
+		int wcw = WCWIDTH(wc);
+		if (wcw > 0)
+                    num += wcw;
+	    }
+
+            /* Reached the width?
+             * If single-width char 'd' reaches width say 4 it'll look like:
+             *     abcd|ef
+             * `e' is the returned (by index) character.
+             *
+             * If double-width char (de) reaches the width:
+             *     abc(d|e)f
+             * `f' is the returned (by index) character
+             * */
+            if (num >= width) {
+                /* We now need to return the next index,
+                 * after we check it exists */
+                if( *ptr )
+                    return index+1;
+                else
+                    return -1;
+            }
+
+	    laststart = ptr;
+	    num_in_char = 0;
+	}
+    }
+
+    /* We choose to point to incomplete character if it's post the width */
+    if (num + (num_in_char > 0 ? 1 : 0) > width) {
+        return index+1;
+    }
+
+    return -1;
+}
+
 /**/
 #else
 
diff --git a/Test/D10width.ztst b/Test/D10width.ztst
new file mode 100644
index 0000000..97e6c11
--- /dev/null
+++ b/Test/D10width.ztst
@@ -0,0 +1,43 @@
+# Test the (y:width:) flag
+
+%test
+
+  setopt multibyte
+  a="測試a句"
+  print ${(y:0:)a}
+  print ${(y:1:)a}
+  print ${(y:2:)a}
+  print ${(y:3:)a}
+  print ${(y:4:)a}
+  print ${(y:5:)a}
+  print ${(y:6:)a}
+  print ${(y:7:)a}
+0:index-post-width for strings
+> 1
+> 2
+> 2
+> 3
+> 3
+> 4
+> -1
+> -1
+
+  setopt multibyte
+  a=( "測試a句" "測" "a" "句句" )
+  print ${(y:0:)a}
+  print ${(y:1:)a}
+  print ${(y:7:)a}
+  print ${(y:8:)a}
+  print ${(y:9:)a}
+  print ${(y:10:)a}
+  print ${(y:11:)a}
+  print ${(y:14:)a}
+0:index-post-width for arrays
+> 1
+> 2
+> 2
+> 3
+> 3
+> 4
+> -1
+> -1
