Add Mockup browser component (#3276)

This commit is contained in:
Paweł Kuna authored and GitHub committed 2026-10-08 14:20:34 +02:00
1 parent 69c1114f7a
commit d6cfffb4df
12 files changed
+479 -1

No files matched your search

+7
View File
@@ -0,0 +1,7 @@
---
'@tabler/core': minor
'@tabler/preview': minor
'@tabler/docs': minor
---
Added the mockup browser component: `.mockup-browser` wraps a screenshot or any content in a frame that looks like a browser window, with window dots and an address bar.
+1
View File
@@ -76,6 +76,7 @@
@forward 'ui/lists';
@forward 'ui/loaders';
@forward 'ui/login';
@forward 'ui/mockup-browser';
@forward 'ui/modals';
@forward 'ui/nav';
@forward 'ui/nav-overflow';
+1
View File
@@ -9,6 +9,7 @@ $darken-dark: adjust-lightness-css(var(--dark), -2%) !default;
$border-color-dark: adjust-lightness-css(var(--dark), 8%) !default;
$border-color-translucent-dark: rgba(128, 150, 172, 0.2) !default;
$border-dark-color-dark: adjust-lightness-css(var(--dark), 4%) !default;
$border-light-color-dark: adjust-lightness-css(var(--dark), 6%) !default;
$border-active-color-dark: adjust-lightness-css(var(--dark), 12%) !default;
//new bootsrap variables
+28
View File
@@ -1794,6 +1794,34 @@ $text-shimmer-loader-duration: 0.75s !default;
$text-shimmer-loader-opacity: 0.25 !default;
// scss-docs-end text-shimmer-variables
// Mockup browser
// scss-docs-start mockup-browser-variables
$mockup-browser-bg: var(--bg-surface) !default;
$mockup-browser-border-color: var(--border-light-color) !default;
$mockup-browser-border-radius: var(--border-radius-lg) !default;
$mockup-browser-box-shadow: var(--shadow-lg) !default;
$mockup-browser-toolbar-min-height: 2rem !default;
$mockup-browser-toolbar-padding-y: 0.5rem !default;
$mockup-browser-toolbar-padding-x: 12.5% !default;
$mockup-browser-toolbar-color: var(--secondary) !default;
$mockup-browser-toolbar-bg: var(--bg-surface-secondary) !default;
$mockup-browser-control-offset: 1rem !default;
$mockup-browser-control-size: 0.75rem !default;
$mockup-browser-control-gap: 0.5rem !default;
$mockup-browser-control-colors: #ff5f57, #febc2e, #28c840 !default;
$mockup-browser-url-font-size: $h5-font-size !default;
$mockup-browser-url-line-height: 1rem !default;
$mockup-browser-url-icon-size: 0.875rem !default;
$mockup-browser-sm-border-radius: var(--border-radius) !default;
$mockup-browser-sm-toolbar-min-height: 1.5rem !default;
$mockup-browser-sm-toolbar-padding-y: 0.25rem !default;
$mockup-browser-sm-control-size: 0.5rem !default;
$mockup-browser-sm-control-gap: 0.25rem !default;
$mockup-browser-sm-url-font-size: $h6-font-size !default;
$mockup-browser-sm-url-icon-size: 0.75rem !default;
// scss-docs-end mockup-browser-variables
// Steps
// scss-docs-start steps-variables
$steps-border-width: 2px !default;
+2 -1
View File
@@ -43,7 +43,7 @@
--border-color-translucent: light-dark(#{$border-color-translucent}, var(--dark-mode-border-color-translucent));
--border-dark-color: light-dark(#{$border-dark-color}, var(--dark-mode-border-dark-color));
--border-dark-color-translucent: #{$border-dark-color-translucent};
--border-light-color: #{$border-light-color};
--border-light-color: light-dark(#{$border-light-color}, var(--dark-mode-border-light-color));
--border-light-color-translucent: #{$border-light-color-translucent};
--border-active-color: light-dark(#{$border-active-color}, var(--dark-mode-border-active-color));
--border-active-color-translucent: #{$border-active-color-translucent};
@@ -65,6 +65,7 @@
--dark-mode-border-color-translucent: #{$border-color-translucent-dark};
--dark-mode-border-active-color: #{$border-active-color-dark};
--dark-mode-border-dark-color: #{$border-dark-color-dark};
--dark-mode-border-light-color: #{$border-light-color-dark};
--page-padding: #{$page-padding};
--page-padding-y: #{$page-padding-y};
+111
View File
@@ -0,0 +1,111 @@
@use 'sass:list';
@use '../config' as *;
// A frame that looks like a browser window, to show a page preview or a screenshot
.mockup-browser {
// scss-docs-start mockup-browser-css-vars
--mockup-browser-bg: #{$mockup-browser-bg};
--mockup-browser-border-color: #{$mockup-browser-border-color};
--mockup-browser-border-radius: #{$mockup-browser-border-radius};
--mockup-browser-box-shadow: #{$mockup-browser-box-shadow};
--mockup-browser-toolbar-min-height: #{$mockup-browser-toolbar-min-height};
--mockup-browser-toolbar-padding-y: #{$mockup-browser-toolbar-padding-y};
--mockup-browser-toolbar-padding-x: #{$mockup-browser-toolbar-padding-x};
--mockup-browser-toolbar-color: #{$mockup-browser-toolbar-color};
--mockup-browser-toolbar-bg: #{$mockup-browser-toolbar-bg};
--mockup-browser-control-offset: #{$mockup-browser-control-offset};
--mockup-browser-control-size: #{$mockup-browser-control-size};
--mockup-browser-control-gap: #{$mockup-browser-control-gap};
--mockup-browser-control-color-1: #{list.nth($mockup-browser-control-colors, 1)};
--mockup-browser-control-color-2: #{list.nth($mockup-browser-control-colors, 2)};
--mockup-browser-control-color-3: #{list.nth($mockup-browser-control-colors, 3)};
--mockup-browser-url-font-size: #{$mockup-browser-url-font-size};
--mockup-browser-url-line-height: #{$mockup-browser-url-line-height};
--mockup-browser-url-icon-size: #{$mockup-browser-url-icon-size};
// scss-docs-end mockup-browser-css-vars
display: flex;
flex-direction: column;
overflow: hidden;
background: var(--mockup-browser-bg);
border: var(--border-width) solid var(--mockup-browser-border-color);
box-shadow: var(--mockup-browser-box-shadow);
@include border-radius(var(--mockup-browser-border-radius));
}
// Small: a 24px toolbar for thumbnails and cards
.mockup-browser-sm {
--mockup-browser-border-radius: #{$mockup-browser-sm-border-radius};
--mockup-browser-toolbar-min-height: #{$mockup-browser-sm-toolbar-min-height};
--mockup-browser-toolbar-padding-y: #{$mockup-browser-sm-toolbar-padding-y};
--mockup-browser-control-size: #{$mockup-browser-sm-control-size};
--mockup-browser-control-gap: #{$mockup-browser-sm-control-gap};
--mockup-browser-url-font-size: #{$mockup-browser-sm-url-font-size};
--mockup-browser-url-icon-size: #{$mockup-browser-sm-url-icon-size};
}
// The top bar: the window dots sit at the start, the address bar fills the middle
.mockup-browser-toolbar {
position: relative;
display: flex;
align-items: center;
min-height: var(--mockup-browser-toolbar-min-height);
padding: var(--mockup-browser-toolbar-padding-y) var(--mockup-browser-toolbar-padding-x);
color: var(--mockup-browser-toolbar-color);
background: var(--mockup-browser-toolbar-bg);
// Drawn as an inset shadow so the line does not add to the toolbar height
box-shadow: inset 0 calc(-1 * var(--border-width)) var(--mockup-browser-border-color);
}
// The three window dots, drawn with one element and two shadows. They are taken
// out of the flow so the address bar stays centered whatever the frame width
.mockup-browser-controls {
position: absolute;
inset-inline-start: var(--mockup-browser-control-offset);
width: var(--mockup-browser-control-size);
height: var(--mockup-browser-control-size);
background: var(--mockup-browser-control-color-1);
border-radius: 50%;
box-shadow:
calc(var(--mockup-browser-control-size) + var(--mockup-browser-control-gap)) 0 0 var(--mockup-browser-control-color-2),
calc(2 * (var(--mockup-browser-control-size) + var(--mockup-browser-control-gap))) 0 0 var(--mockup-browser-control-color-3);
}
// The address, plain centered text
.mockup-browser-url {
display: flex;
gap: 0.25rem;
align-items: center;
justify-content: center;
width: 100%;
min-width: 0;
font-size: var(--mockup-browser-url-font-size);
line-height: var(--mockup-browser-url-line-height);
> span {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.icon {
--icon-size: var(--mockup-browser-url-icon-size);
flex-shrink: 0;
}
}
// The page: a screenshot fills the width, other content keeps its own layout
.mockup-browser-body {
flex: 1;
min-height: 0;
> img,
> iframe,
> video {
display: block;
width: 100%;
}
> iframe {
border: 0;
}
}
@@ -0,0 +1,152 @@
---
title: Mockup browser
summary: A mockup browser is a frame that looks like a browser window, with the window dots and an address bar, to show a page preview or a screenshot.
description: Show a screenshot or any content inside a browser window frame with the mockup browser component. Add an address, a lock icon or your own colors.
related: [/ui/components/image-label, /ui/components/card]
source: core/scss/ui/_mockup-browser.scss
css-vars: mockup-browser
classnames:
component:
- class: mockup-browser
desc: The frame, with a border, rounded corners and a shadow
size:
- class: mockup-browser-sm
desc: A 24px toolbar with smaller dots and text, for thumbnails and cards
part:
- class: mockup-browser-toolbar
desc: The top bar with the window dots and the address bar
- class: mockup-browser-controls
desc: The three window dots
- class: mockup-browser-url
desc: The address, centered in the toolbar
- class: mockup-browser-body
desc: The page area that holds the screenshot or the content
---
import Example from '@components/Example.astro';
import Icon from '@ui/Icon.astro';
## Default markup
A `.mockup-browser` has a `.mockup-browser-toolbar` with the window dots and an address bar, and a `.mockup-browser-body` with the page. An image in the body fills the width of the frame.
<Example>
<div class="mockup-browser">
<div class="mockup-browser-toolbar">
<span class="mockup-browser-controls"></span>
<div class="mockup-browser-url"><span>preview.tabler.io</span></div>
</div>
<div class="mockup-browser-body">
<img src="/static/tabler-preview.png" srcset="/static/tabler-preview.png 1x, /static/tabler-preview@2x.png 2x" class="hide-theme-dark" alt="Tabler dashboard" />
<img src="/static/tabler-preview-dark.png" srcset="/static/tabler-preview-dark.png 1x, /static/tabler-preview-dark@2x.png 2x" class="hide-theme-light" alt="Tabler dashboard" />
</div>
</div>
</Example>
## Secure address
Put an icon before the address text to show a secure page. The icon is scaled down to match the text.
<Example>
<div class="mockup-browser">
<div class="mockup-browser-toolbar">
<span class="mockup-browser-controls"></span>
<div class="mockup-browser-url"><Icon name="lock" /><span>https://preview.tabler.io</span></div>
</div>
<div class="mockup-browser-body">
<img src="/static/tabler-preview.png" srcset="/static/tabler-preview.png 1x, /static/tabler-preview@2x.png 2x" class="hide-theme-dark" alt="Tabler dashboard" />
<img src="/static/tabler-preview-dark.png" srcset="/static/tabler-preview-dark.png 1x, /static/tabler-preview-dark@2x.png 2x" class="hide-theme-light" alt="Tabler dashboard" />
</div>
</div>
</Example>
## Without an address bar
Leave out `.mockup-browser-url` for a plain window frame with only the dots.
<Example>
<div class="mockup-browser">
<div class="mockup-browser-toolbar">
<span class="mockup-browser-controls"></span>
</div>
<div class="mockup-browser-body">
<img src="/static/tabler-preview.png" srcset="/static/tabler-preview.png 1x, /static/tabler-preview@2x.png 2x" class="hide-theme-dark" alt="Tabler dashboard" />
<img src="/static/tabler-preview-dark.png" srcset="/static/tabler-preview-dark.png 1x, /static/tabler-preview-dark@2x.png 2x" class="hide-theme-light" alt="Tabler dashboard" />
</div>
</div>
</Example>
## Sizes
Add `.mockup-browser-sm` for a 24px toolbar with smaller dots and text. Use it for thumbnails and for frames inside cards.
<Example>
<div class="row g-3 align-items-start">
<div class="col-md-7">
<div class="mockup-browser">
<div class="mockup-browser-toolbar">
<span class="mockup-browser-controls"></span>
<div class="mockup-browser-url"><Icon name="lock" /><span>preview.tabler.io</span></div>
</div>
<div class="mockup-browser-body">
<img src="/static/tabler-preview.png" srcset="/static/tabler-preview.png 1x, /static/tabler-preview@2x.png 2x" class="hide-theme-dark" alt="Tabler dashboard" />
<img src="/static/tabler-preview-dark.png" srcset="/static/tabler-preview-dark.png 1x, /static/tabler-preview-dark@2x.png 2x" class="hide-theme-light" alt="Tabler dashboard" />
</div>
</div>
</div>
<div class="col-md-5">
<div class="mockup-browser mockup-browser-sm">
<div class="mockup-browser-toolbar">
<span class="mockup-browser-controls"></span>
<div class="mockup-browser-url"><Icon name="lock" /><span>preview.tabler.io</span></div>
</div>
<div class="mockup-browser-body">
<img src="/static/tabler-preview.png" srcset="/static/tabler-preview.png 1x, /static/tabler-preview@2x.png 2x" class="hide-theme-dark" alt="Tabler dashboard" />
<img src="/static/tabler-preview-dark.png" srcset="/static/tabler-preview-dark.png 1x, /static/tabler-preview-dark@2x.png 2x" class="hide-theme-light" alt="Tabler dashboard" />
</div>
</div>
</div>
</div>
</Example>
## Any content
The body takes any markup, not only an image. Add a padding utility to the body when the content needs space from the frame.
<Example>
<div class="mockup-browser">
<div class="mockup-browser-toolbar">
<span class="mockup-browser-controls"></span>
<div class="mockup-browser-url"><Icon name="lock" /><span>example.com/signup</span></div>
</div>
<div class="mockup-browser-body p-4">
<h3 class="card-title">Create an account</h3>
<div class="mb-3">
<label class="form-label" for="mockup-browser-email">Email</label>
<input type="email" class="form-control" id="mockup-browser-email" placeholder="you@example.com" />
</div>
<button type="button" class="btn btn-primary w-100">Sign up</button>
</div>
</div>
</Example>
## Custom look
Set the `--tblr-mockup-browser-*` variables on the frame to change the colors, the shadow or the size of the dots. The three dots have their own color variables, `--tblr-mockup-browser-control-color-1` to `-3`.
<Example>
<div class="mockup-browser" style="--tblr-mockup-browser-toolbar-bg: var(--tblr-gray-900); --tblr-mockup-browser-toolbar-color: var(--tblr-gray-400); --tblr-mockup-browser-border-color: var(--tblr-gray-900); --tblr-mockup-browser-box-shadow: none">
<div class="mockup-browser-toolbar">
<span class="mockup-browser-controls"></span>
<div class="mockup-browser-url"><Icon name="lock" /><span>preview.tabler.io</span></div>
</div>
<div class="mockup-browser-body">
<img src="/static/tabler-preview-dark.png" srcset="/static/tabler-preview-dark.png 1x, /static/tabler-preview-dark@2x.png 2x" alt="Tabler dashboard" />
</div>
</div>
</Example>
## Accessibility
- The window dots are decoration. They are an empty element, so screen readers skip them.
- The address bar is plain text and is read as such. It is not a link and not a form field.
- Give a screenshot in the body an `alt` text that says what page it shows.
+118
View File
@@ -0,0 +1,118 @@
---
import DefaultLayout from '@shared/layouts/DefaultLayout.astro'
import Card from '@ui/Card.astro'
import CardBody from '@ui/CardBody.astro'
import CardTitle from '@ui/CardTitle.astro'
import CardSubtitle from '@ui/CardSubtitle.astro'
import DocsLink from '@ui/DocsLink.astro'
import MockupBrowser from '@ui/MockupBrowser.astro'
import Button from '@ui/Button.astro'
---
<DefaultLayout title="Mockup browser" pageMenu="base.mockup-browser" description="The mockup browser shows a page preview or a screenshot inside a frame that looks like a browser window.">
<DocsLink slot="page-header-actions" path="/ui/components/mockup-browser" />
<div class="row row-cards">
<div class="col-lg-6">
<Card>
<CardBody>
<CardTitle>Basic</CardTitle>
<CardSubtitle>A screenshot in a <code>.mockup-browser</code> frame, with the window dots and an address bar.</CardSubtitle>
<MockupBrowser url="preview.tabler.io">
<div class="ratio ratio-16x9">
<div class="d-flex align-items-center justify-content-center text-secondary">Your page goes here</div>
</div>
</MockupBrowser>
</CardBody>
</Card>
</div>
<div class="col-lg-6">
<Card>
<CardBody>
<CardTitle>Secure address</CardTitle>
<CardSubtitle>Put a lock icon before the address to show a secure page.</CardSubtitle>
<MockupBrowser url="https://preview.tabler.io" secure>
<div class="ratio ratio-16x9">
<div class="d-flex align-items-center justify-content-center text-secondary">Your page goes here</div>
</div>
</MockupBrowser>
</CardBody>
</Card>
</div>
<div class="col-lg-6">
<Card>
<CardBody>
<CardTitle>Without an address bar</CardTitle>
<CardSubtitle>Leave out <code>.mockup-browser-url</code> for a plain window frame.</CardSubtitle>
<MockupBrowser>
<div class="ratio ratio-16x9">
<div class="d-flex align-items-center justify-content-center text-secondary">Your page goes here</div>
</div>
</MockupBrowser>
</CardBody>
</Card>
</div>
<div class="col-12">
<Card>
<CardBody>
<CardTitle>Sizes</CardTitle>
<CardSubtitle>Add <code>.mockup-browser-sm</code> for a 24px toolbar with smaller dots and text, for thumbnails and cards.</CardSubtitle>
<div class="row g-3 align-items-start">
<div class="col-md-7">
<MockupBrowser url="preview.tabler.io" secure>
<div class="ratio ratio-16x9">
<div class="d-flex align-items-center justify-content-center text-secondary">Your page goes here</div>
</div>
</MockupBrowser>
</div>
<div class="col-md-5">
<MockupBrowser url="preview.tabler.io" secure size="sm">
<div class="ratio ratio-16x9">
<div class="d-flex align-items-center justify-content-center text-secondary">Your page goes here</div>
</div>
</MockupBrowser>
</div>
</div>
</CardBody>
</Card>
</div>
<div class="col-lg-6">
<Card>
<CardBody>
<CardTitle>Any content</CardTitle>
<CardSubtitle>The body takes any markup, not only an image, so a component can be shown as a page.</CardSubtitle>
<MockupBrowser url="example.com/signup" secure bodyClass="p-4">
<h3 class="card-title">Create an account</h3>
<div class="mb-3">
<label class="form-label" for="mockup-browser-email">Email</label>
<input type="email" class="form-control" id="mockup-browser-email" placeholder="you@example.com" />
</div>
<div class="mb-3">
<label class="form-label" for="mockup-browser-password">Password</label>
<input type="password" class="form-control" id="mockup-browser-password" placeholder="Password" />
</div>
<Button color="primary" class="w-100" text="Sign up" />
</MockupBrowser>
</CardBody>
</Card>
</div>
<div class="col-lg-6">
<Card>
<CardBody>
<CardTitle>Custom look</CardTitle>
<CardSubtitle>Set the <code>--tblr-mockup-browser-*</code> variables for a dark toolbar, other window dot colors or no shadow.</CardSubtitle>
<MockupBrowser url="preview.tabler.io" secure style="--tblr-mockup-browser-toolbar-bg: var(--tblr-gray-900); --tblr-mockup-browser-toolbar-color: var(--tblr-gray-400); --tblr-mockup-browser-border-color: var(--tblr-gray-900); --tblr-mockup-browser-box-shadow: none">
<div class="ratio ratio-16x9">
<div class="d-flex align-items-center justify-content-center text-secondary">Your page goes here</div>
</div>
</MockupBrowser>
</CardBody>
</Card>
</div>
</div>
</DefaultLayout>
+13
View File
@@ -0,0 +1,13 @@
---
// Mockup browser on its own, no card: one frame with the lock icon and the
// Tabler dashboard screenshot, light and dark through the hide-theme classes.
import ScreenshotLayout from '../layouts/ScreenshotLayout.astro'
import MockupBrowser from '@ui/MockupBrowser.astro'
---
<ScreenshotLayout title="Mockup browser" columns={2}>
<MockupBrowser url="https://preview.tabler.io" secure>
<img src="/static/tabler-preview@2x.png" class="hide-theme-dark" alt="" />
<img src="/static/tabler-preview-dark@2x.png" class="hide-theme-light" alt="" />
</MockupBrowser>
</ScreenshotLayout>
+4
View File
@@ -254,6 +254,10 @@
"title": "Modal",
"url": "/ui/components/modal"
},
{
"title": "Mockup browser",
"url": "/ui/components/mockup-browser"
},
{
"title": "Nav overflow",
"url": "/ui/components/nav-overflow"
+5
View File
@@ -190,6 +190,11 @@
"url": "modals.html",
"title": "Modals"
},
"mockup-browser": {
"url": "mockup-browser.html",
"title": "Mockup browser",
"badge": "New"
},
"prose": {
"title": "Prose",
"url": "prose.html"
+37
View File
@@ -0,0 +1,37 @@
---
// Mockup browser (.mockup-browser): a frame that looks like a browser window,
// with the window dots and an address bar above the content in the slot.
interface Props {
/** text shown in the address bar; no address bar when omitted */
url?: string | undefined
/** show a lock icon before the url */
secure?: boolean
/** `.mockup-browser-sm`: a 24px toolbar for thumbnails and cards */
size?: 'sm'
class?: string
/** class of the `.mockup-browser-body` element */
bodyClass?: string | undefined
/** remaining attributes (id, data-*, aria-*, …) are forwarded to the root element */
[key: string]: unknown
}
import Icon from './Icon.astro'
const { url, secure, size, class: className, bodyClass, ...rest } = Astro.props
---
<div class:list={['mockup-browser', size && `mockup-browser-${size}`, className]} {...rest}>
<div class="mockup-browser-toolbar">
<span class="mockup-browser-controls"></span>
{
url && (
<div class="mockup-browser-url">
{secure && <Icon name="lock" />}
<span>{url}</span>
</div>
)
}
</div>
<div class:list={['mockup-browser-body', bodyClass]}><slot /></div>
</div>