Action Sheet
ورقة الإجراءاتUIAlertController .actionSheet
also calledoptions sheet، confirmation dialog، UIActionSheet، iOS options menu، bottom action menu، أكشن شيت، قائمة الإجراءات، ورقة الخيارات، قائمة الأوامر السفلية، شيت الخيارات، ورقة التأكيد
An action sheet is a short list of commands about one object, and it rises from the bottom edge of the screen to block whatever is under it until the user picks one or cancels. It came from iOS, where it is a UIAlertController created with preferredStyle .actionSheet. It is not a bottom sheet: a bottom sheet takes arbitrary content such as a form, a map, or a long list, its height belongs to the user who drags it between detents, and it can sit on screen with no scrim at all, while an action sheet is only as tall as its commands make it, cannot be dragged, and has no non-blocking form. It is not an alert: an alert stands in the middle of the screen and asks one question with two answers, where an action sheet lists what can be done to the thing it was opened from. It is not a menu either: a menu hangs off the control that opened it and its rows can carry an icon, a checkmark, or a submenu, while an action sheet is pinned to the bottom edge whatever opened it and every row is a plain centred label. On the phone it is modal and ends with a cancel row set apart from the rest; on iPad the same call becomes a popover that draws no cancel row. The moment a text field, an image, or a seventh command goes in, the right name is bottom sheet.
If you called it…
Live specimen
Interact with the demo. Every part is real and numbered.
آخر أمر نُفّذ: لا شيء بعد
صورة الرحلة
الحذف لا يمكن التراجع عنه
Anatomy: every part, named
Hover a row to locate it in the demo above.
Build prompt
How it behaves right-to-left
This section is ours alone.
The rows have nothing to mirror
never mirrorsAn action row takes the full inline size of the sheet with its label centred, so it has no start and no end to swap, and UIAlertAction gives you no alignment knob anyway. The risk is in hand-written versions: text-align: left inside a row leaves the Arabic label hanging on the left after the rest of the screen has flipped. Write text-align: center to match the iOS form, or text-align: start if you align the names to the beginning of the line the way Material list rows do.
The leading icon
mirrorsWhere a row does carry an icon before its name, as in Material list rows or a hand-written web sheet, that icon belongs at the logical start and lands on the right of the row in Arabic. Build the row with flex, gap, and padding-inline-start, never padding-left or margin-right, and remember that on Android nothing moves until android:supportsRtl="true" is in the manifest. Only a directional glyph also flips its own drawing: take those from Icons.AutoMirrored in Compose or from imageFlippedForRightToLeftLayoutDirection() in UIKit, and leave the trash can and the share glyph alone.
The destructive row keeps its colour and its slot
never mirrorsNothing about the destructive row mirrors: the red is a state rather than a direction, and its slot at the top of the sheet is the same in both languages. Row order runs down the block axis, which direction never touches, so flex-direction: column-reverse has no business anywhere near this list. The recurring mistake is a blanket [dir="rtl"] svg { transform: scaleX(-1) }, which flips the trash glyph with everything else and leaves it drawn back to front; transform has no logical counterpart, so scope that rule to the icons that really are directional.
The popover anchor on iPad
mirrorsThe tablet form grows out of whatever opened it, so it follows that control's logical side: a button at the end of the navigation bar opens the popover on the left in Arabic after opening on the right in English. The trap is sourceRect, a physical CGRect in the source view's own coordinate space, so CGRect(x: view.bounds.width - 44, …) stays pinned to the right whatever the interface direction is. Pass sourceItem or barButtonItem and let UIKit compute the frame, or read view.effectiveUserInterfaceLayoutDirection and mirror x yourself. permittedArrowDirections is physical in the same way, since .left and .right have no logical twin, so swap them with the direction or settle for .any.
The Arabic name is a different length
never mirrorsArabic does not track English length: «حذف» is half of Delete in characters, while «إضافة إلى الشاشة الرئيسية» runs a third longer than Add to Home Screen. The native sheet wraps a long title onto a second line and grows the row, and hand-written versions break that with a fixed row height, with white-space: nowrap plus text-overflow: ellipsis, or with maxLines = 1 in Compose. Swap height for min-block-size and leave the label wrapping, because clipping the end of an Arabic command drops its object, the part that says what the command acts on. Arabic also needs a taller line box than Latin at the same size, so a line-height tuned on English clips the descenders of ج and ح and the dots under ي.
In code
Each row is one framework's word for the same thing. Take the row your project speaks.
See also
Updated · 2026-08-19