Sheet
A panel flush against an edge, with the page still visible beside it. Four positions built out of child order and a justify, and nothing rotated.
The overlay and the panel are two siblings in one flex box. right and left swap which of them comes first and flip the justify; top and bottom do the same with the direction set to column. Nothing is rotated and nothing is moved by hand, which is why all four stay in step.
Radius is zero on all four. A sheet is flush against an edge of the screen, so rounding it would leave two curves floating against a straight edge. That is the difference between this and a Dialog, which is centred and rounded on all four corners.
Four parts in 24 of padding, 16 apart. The content block is base.muted on radius.md and takes whatever height is left; the footer stacks two full-width buttons 8 apart rather than putting them in a row, because a panel this narrow cannot fit two side by side at a readable width.
A scrim you can see through
The point of the dark half is to say the page is still there and you are coming back to it. Half strength is the setting, matching the source; at full strength it stops being a scrim and becomes a wall, and the sheet may as well have been a new screen. Step through the three.
Sixteen pixels in the corner
Its own component with three states: base.muted-foreground at rest, base.foreground on hover, and a base.ring around it on focus. It sits absolutely, 24 in from the panel's top right, so it does not take part in the column layout and never pushes the header down.
All four Sheet positions carry a real instance of this component, so a change here reaches every panel. The source also has a showCloseButton prop that removes it altogether, which the file does not draw as a variant - hide the layer on your instance if you need that.
Open one from each edge
The one thing a still frame cannot show: the panel comes in from the edge it belongs to. Click the overlay, the close, or Cancel to send it back. The scrim here is at 50 percent, because that is what the component is for.
A sheet is for the work beside the work: editing one record, filtering a list, reading a detail. The page stays where it was, which is why the scrim is see-through.
An edit panel and a filter panel
1344 by 972, holding two instances resized to 700 tall. Editing comes in from the right, where a tall narrow column suits a form; filtering comes up from the bottom, which is the shape that works on a phone and reads as temporary on a desktop.
The bottom one is where resizing an instance used to show its teeth. Its overlay was a fixed 300 tall inside a column layout, so shortening the board from 867 to 700 left the pair 167 too long and the overflow was clipped away above the frame - it looked right and was not. The overlay is set to fill now, so it takes whatever the panel leaves and the arithmetic holds at any height: 133 and 567 here, 300 and 567 in the component itself.
Two components, seven variants
Read straight out of the Penpot file. The axes below are the property names you will see in the variant dropdown.
Using the Sheet
Out of two siblings in one flex box. The overlay and the panel sit side by side; right and left swap which comes first and flip the justify, and top and bottom do the same with the direction set to column. Nothing is rotated and no child is placed by hand, which is why the four cannot drift apart.
Because it is flush against an edge. Radius is zero on all four positions - rounding a panel that touches the side of the screen leaves two curves floating against a straight line. That is the visible difference between a Sheet and a Dialog, which is centred and rounded on every corner.
Because the panel is 388 wide with 24 of padding on each side, leaving 340. Two buttons in a row would be 166 each before the gap, which is narrower than most labels want. The footer is a column with an 8 gap and both buttons at full width, and both are real Button instances rather than drawn rectangles.
A base.muted rectangle on radius.md holding the words Your content goes here, and it is the only part of the panel that grows. Header and footer hug their contents; the block takes whatever height is left. Replace it with your own and the panel keeps working at any height.
In the source, yes - showCloseButton on SheetContent removes it. There is no variant for that, so hide the layer on your instance. The close itself is 16 by 16 sitting absolutely 24 in from the panel's top right, outside the column layout, so it can never push the header down.