# TallStackUI: Modal > TallStackUI is a TALL Stack (Tailwind CSS, Alpine.js, Laravel, Livewire) > component library providing 80+ Blade components for building modern web interfaces. A modal overlay component for displaying content in a centered or top-aligned dialog with optional title, footer, blur backdrop, scrollable body, and configurable sizes. Can be controlled via `wire:model`, JavaScript API, or Livewire events. The vertical alignment is responsive: `center` accepts a boolean or a Tailwind breakpoint, so the modal can be a bottom sheet on the phone and a centered dialog on the desktop. ## Basic Usage ```blade

Modal body content goes here.

``` ```blade

Are you sure you want to continue?

``` Using `wire:model` for Livewire-controlled state: ```blade

Controlled by a Livewire property.

``` Centering only from a breakpoint upwards. Below it the modal stays a bottom sheet, at every width, with no top-aligned band in between: ```blade ``` | Value | Alignment classes | |---------|--------------------------------------------| | `false` | `items-end sm:items-start` | | `true` | `items-center` plus `p-4` and `rounded-xl` | | `"sm"` | `items-end sm:items-center` | | `"md"` | `items-end md:items-center` | | `"lg"` | `items-end lg:items-center` | | `"xl"` | `items-end xl:items-center` | | `"2xl"` | `items-end 2xl:items-center` | Only `center` as a boolean forces `p-4` and `rounded-xl`, which makes the modal float free of the screen edges on mobile too. A breakpoint keeps the mobile bottom sheet flush and relies on the `sm:` variants the wrapper blocks already carry, so from `sm` up the sheet gains its padding and full radius while staying anchored to the bottom until the chosen breakpoint takes over. ## Open Animation Below `sm` the modal is a bottom sheet and slides in opaque from off screen, with no fade, over 400ms of `ease-emphasized-decelerate`. It leaves over 200ms of `ease-emphasized-accelerate`. From `sm` up it is a floating dialog again and fades while it scales. The backdrop fades in both cases. `center` as a boolean never slides: it is a centered dialog at every width, so it scales in even on a phone. A breakpoint keeps the sheet, and therefore the slide, below `sm`. Under `prefers-reduced-motion` the sheet stops travelling and fades instead. The two easing tokens live in `css/v4.css` and are available to any component: ```css --ease-emphasized-decelerate: cubic-bezier(0.05, 0.7, 0.1, 1); --ease-emphasized-accelerate: cubic-bezier(0.3, 0, 0.8, 0.15); ``` Removing the body padding so the content bleeds to the edges. The title and the footer keep theirs: ```blade ``` Distributing the footer actions instead of pushing them all to the end: ```blade

Body content.

``` Taking over the footer layout with `unwrapped`. The border and the padding of the footer area stay; only the aligning wrapper is dropped: ```blade

Body content.

``` ## Attributes | Attribute | Type | Default | Description | |-------------|--------------------|----------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | id | string\|null | 'modal' | Unique identifier used for targeting with JS API and events | | zIndex | string\|null | null (from config: 'z-50') | CSS z-index class | | wire | string\|bool\|null | null | Livewire entangle property name (string) or boolean to use default 'modal' | | title | string\|null | null | Title text displayed in the modal header with a close button | | footer | string\|null | null | Footer slot content | | blur | bool\|string\|null | null (from config: false) | Backdrop blur effect (false, sm, md, lg, xl, or true for sm) | | persistent | bool\|null | null (from config: false) | When true, prevents closing via outside click or Escape key | | size | string\|null | null (from config: '2xl') | Modal width (sm, md, lg, xl, 2xl, 3xl, 4xl, 5xl, 6xl, 7xl, full) | | entangle | string\|null | 'modal' | Livewire property name for entangle binding | | center | bool\|string\|null | null (from config: false) | `true` centers on all viewport sizes with full border radius and padding (v2-style). A breakpoint (sm, md, lg, xl, 2xl) centers only from that width upwards, staying a bottom sheet below it | | overflow | bool\|null | null (from config: false) | When true, avoids hiding body overflow | | scrollable | bool\|null | null (from config: false) | When true, fixes title and footer while body scrolls | | paddingless | bool\|null | null | When true, removes the padding of the body, leaving the default slot flush against the modal edges. Title and footer keep their padding | | handle | bool\|null | null (from config: false) | Displays a grabber bar on mobile only (`sm:hidden`) allowing the bottom sheet to be dragged down to close. Releases beyond 25% of the panel height dismiss; pulling upwards meets rubber band resistance | ## Slots | Slot | Description | |-----------|----------------------------------------------------------------| | (default) | Main body content of the modal | | title | Title text or custom markup in the modal header (as attribute) | | footer | Content rendered in the modal footer area | ### Footer Slot Attributes | Attribute | Description | |-----------|--------------------------------------------------------------------| | start | Aligns the footer content to the start | | center | Centers the footer content | | end | Aligns the footer content to the end (default when none is passed) | | between | Distributes the footer content with space between | | unwrapped | Drops the aligning wrapper, keeping the footer border and padding | ## Validation Constraints - The `wire` property cannot be an empty string. - The `size` must be one of: sm, md, lg, xl, 2xl, 3xl, 4xl, 5xl, 6xl, 7xl, full. - The `center` must be a boolean or one of: sm, md, lg, xl, 2xl. This rejects `center="desktop"` and `center="true"`, since Blade hands a quoted attribute over as a string. Arbitrary values such as `center="min-[900px]"` are not supported: Tailwind only generates classes it can read literally in the source. - The `handle` cannot be used when `center` is fully enabled (`center` as `true`): a centered modal never behaves as a bottom sheet. Breakpoint values are fine. - The `zIndex` must start with `z-` prefix. - The `footer` slot cannot combine two or more alignments. - The `footer` slot cannot use `unwrapped` together with an alignment. ## JavaScript Control ```js $tsui.open.modal('my-modal') $tsui.close.modal('my-modal') ``` ## Configuration In `config/tallstackui.php` under `components.modal`: | Option | Type | Default | Description | |------------|---------------|---------|---------------------------------------------------------------------------------------------------------------| | z-index | string | 'z-50' | Default z-index class | | overflow | bool | false | When true, avoids hiding body overflow | | blur | false\|string | false | Backdrop blur effect (false, sm, md, lg, xl) | | persistent | bool | false | When true, prevents closing by clicking outside | | size | string | '2xl' | Default modal width | | center | bool\|string | false | When true, centers on every viewport. A breakpoint (sm, md, lg, xl, 2xl) centers only from that width upwards | | scrollable | bool | false | When true, fixes title/footer while body scrolls | | scrollbar | string\|null | 'thin' | Scrollbar style for scrollable mode (null, thin, thick) | | handle | bool | false | Displays the mobile drag-to-close grabber by default (the inline prop always wins) | ## Wireable Mode (Livewire Property Binding) Use `wire` to bind modal visibility to a Livewire boolean property: ```blade TallStackUi Open ``` Custom property name: ```blade TallStackUi Open ``` The property may already be `true` on the first render, set in `mount()` or through `#[Url]` for instance. The modal then opens with the page and behaves like any other open modal: Escape and a click outside close it, the page scroll is locked and `x-on:open` is dispatched. ## Alpine.js Events ```blade TallStackUi ``` ## Focus Helper Auto-focus an input when the modal opens using `$tsui.focus()`: ```blade
``` Optional delay in milliseconds: `$tsui.focus('email', 1000)` You can also target elements by `data-focus` attribute instead of `id`: ```blade ``` ## Soft Customization Soft customization allows you to override default Tailwind CSS classes used by this component at runtime, either through a service provider or scoped per-instance. ### Customization ```php TallStackUi::customize() ->modal() ->block('wrapper.first', 'your-tailwind-classes'); ``` ### Available Blocks | Block Name | Purpose | |----------------------|-------------------------------------------------| | wrapper.first | Fixed overlay backdrop | | wrapper.second | Fixed full-screen scroll container | | wrapper.third | Centering flex container with size constraint | | wrapper.fourth | Modal card with rounded corners and shadow | | wrapper.scrollable | Max-height constraint for scrollable mode | | positions.top | Alignment classes for top-positioned modal | | positions.center | Alignment classes for centered modal | | positions.center-sm | Alignment when centering from `sm` upwards | | positions.center-md | Alignment when centering from `md` upwards | | positions.center-lg | Alignment when centering from `lg` upwards | | positions.center-xl | Alignment when centering from `xl` upwards | | positions.center-2xl | Alignment when centering from `2xl` upwards | | blur.sm | Small backdrop blur effect | | blur.md | Medium backdrop blur effect | | blur.lg | Large backdrop blur effect | | blur.xl | Extra-large backdrop blur effect | | title.wrapper | Title bar container with border | | title.text | Title heading styles | | title.close | Close button icon styles | | handle.wrapper | Grabber strip container (mobile only) | | handle.bar | Grabber bar styles | | body | Body content area styles | | body.scrollable | Scrollable body overflow styles | | body.paddingless | Padding reset applied when `paddingless` is set | | footer.wrapper | Footer container with border and padding | | footer.scrollable | Sticky footer styles for scrollable mode | | footer.base | Footer aligning wrapper (flex row) | | footer.start | Footer alignment applied by `start` | | footer.center | Footer alignment applied by `center` | | footer.end | Footer alignment applied by `end` (default) | | footer.between | Footer alignment applied by `between` |