mirror of
https://github.com/tabler/tabler.git
synced 2026-08-26 21:04:25 +04:00
Redesign the docs layout and simplify the menu structure (#2902)
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
---
|
||||
name: class-reference
|
||||
description: Write or update the `classnames` front matter that renders the class reference table on a Tabler docs page. Use whenever a component page needs its class list added, a component gains or loses a class in `core/scss/**`, or the user asks for a class reference, a class table, or a `classnames` block. Also consult it proactively after adding a class to an existing component, since the table is hand-written and will not notice on its own.
|
||||
---
|
||||
|
||||
# Class reference front matter
|
||||
|
||||
Every component page carries a `classnames` block in its front matter. `DocsClassnames.astro` renders it as a table at the end of the page, `docs/pages/llms.txt.ts` reprints it for agents, and `docs/content.config.ts` validates it. Editing the table means editing the front matter — there is no markdown table to touch.
|
||||
|
||||
## 1. Shape
|
||||
|
||||
```yaml
|
||||
classnames:
|
||||
component:
|
||||
- class: alert
|
||||
desc: Container element
|
||||
part:
|
||||
- class: alert-icon
|
||||
desc: Icon slot, sized and colored with the alert
|
||||
color:
|
||||
- class: alert-{color}
|
||||
desc: Any base color, for example alert-success or alert-blue
|
||||
```
|
||||
|
||||
The schema is strict (`docs/content.config.ts`), so a mistyped key fails the build. Each entry takes `class`, `desc`, and optionally `default: true`, which renders a "default" badge.
|
||||
|
||||
## 2. The eight types
|
||||
|
||||
Rendered in this order regardless of the order in the file, so group by meaning rather than by position:
|
||||
|
||||
| Type | Holds | Examples |
|
||||
| --- | --- | --- |
|
||||
| `component` | the class that makes the thing | `alert`, `btn`, `card` |
|
||||
| `part` | sub-elements it is built from | `card-header`, `alert-icon` |
|
||||
| `style` | surface treatment | `btn-outline`, `btn-ghost`, `alert-minor` |
|
||||
| `modifier` | shape or box changes | `btn-pill`, `btn-square`, `accordion-flush` |
|
||||
| `behavior` | state and motion | `btn-loading`, `icon-pulse`, `table-hover` |
|
||||
| `direction` | placement and orientation | `offcanvas-start`, `steps-vertical` |
|
||||
| `color` | color variants | `alert-{color}`, `btn-{color}` |
|
||||
| `size` | size variants | `btn-sm`, `avatar-{size}` |
|
||||
|
||||
The split between `style`, `modifier` and `behavior` follows daisyUI: how it looks, what shape it is, how it reacts.
|
||||
|
||||
## 3. Collapse generated families
|
||||
|
||||
Tabler generates colors, sizes, breakpoints and directions with loops. Listing each one turns a reference into a wall — `btn` alone compiles to 141 classes. Write one row with a brace placeholder and say what fills it:
|
||||
|
||||
```yaml
|
||||
- class: btn-{color}
|
||||
desc: Any base or social color, for example btn-primary or btn-facebook
|
||||
- class: table-mobile-{breakpoint}
|
||||
desc: Stacks rows into blocks below the breakpoint
|
||||
- class: switch-icon-slide-{direction}
|
||||
desc: Slides the icons; up, down, left, right, start or end
|
||||
```
|
||||
|
||||
Collapse when the family is mechanical and complete. Keep separate rows when the members differ in meaning — `btn-sm`, `btn-lg` and `btn-xl` are worth spelling out, `flag-country-{code}` is not (258 members).
|
||||
|
||||
## 4. Leave out
|
||||
|
||||
- Classes a script toggles rather than an author writes: `carousel-item-next`, `modal-backdrop`, `accordion-collapse`, `active`, `show`.
|
||||
- Bootstrap utilities that are not part of the component.
|
||||
- Classes that do not exist. This is the failure mode to guard against — see section 6.
|
||||
|
||||
## 5. Writing the description
|
||||
|
||||
Say what the class does, from the rule, not from the name:
|
||||
|
||||
- `alert-minor` — "Drops the tinted background, keeps a plain border", not "minor style".
|
||||
- `td-truncate` — "Cell whose content is cut with an ellipsis instead of stretching the table".
|
||||
|
||||
One line, no trailing period needed, simple English. Read the SCSS before writing:
|
||||
|
||||
```shell
|
||||
sed -n '/^\.alert-minor/,/}/p' core/scss/ui/_alerts.scss
|
||||
```
|
||||
|
||||
## 6. Check every class exists
|
||||
|
||||
Descriptions are hand-written, so a class can be invented or survive a rename. Three wrong entries were caught this way while the tables were first written — `trending` and `map` were never classes at all, and `.map` matched only a stray fragment in the compiled CSS.
|
||||
|
||||
Verify against the compiled stylesheet, and confirm the rule has a body rather than trusting a text match:
|
||||
|
||||
```shell
|
||||
python3 -c "
|
||||
import re
|
||||
css = open('core/dist/css/tabler.css').read()
|
||||
for c in ['alert-minor', 'alert-icon']:
|
||||
m = re.search(r'(^|\})\s*\.' + c + r'\s*\{([^}]*)\}', css)
|
||||
print(c, '->', ' '.join(m.group(2).split())[:70] if m else 'NOT A RULE')
|
||||
"
|
||||
```
|
||||
|
||||
Plugin classes live in their own sheets — `tabler-flags.css`, `tabler-socials.css`, `tabler-payments.css`, `tabler-vendors.css` — so read the right one.
|
||||
|
||||
Components with no class of their own are real: `trending` is built from `text-green` plus an arrow icon, and the map page frames an embed with `ratio`. Document what the page actually uses.
|
||||
|
||||
## 7. Also set `source`
|
||||
|
||||
Pages that carry `classnames` should carry `source` too — the repo-relative file that implements the component, rendered as the "Source code" link:
|
||||
|
||||
```yaml
|
||||
source: core/scss/ui/_alerts.scss
|
||||
```
|
||||
|
||||
Most map to `core/scss/ui/_<name>s.scss`. Exceptions worth knowing: `segmented-control` → `_segmented.scss`, `step` → `_steps.scss`, `star-rating` → `_stars.scss`, `divider` → `_type.scss`, `tab` → `_nav.scss`, `tooltip` → `bootstrap/_tooltip.scss`, `trending` → `shared/ui/Trending.astro`.
|
||||
|
||||
## 8. Finish
|
||||
|
||||
- Load the page and confirm the table renders and "Class reference" reaches the "On this page" rail.
|
||||
- Run `pnpm run lint` and `pnpm --dir docs run type-check`.
|
||||
- New pages also need a menu entry in `shared/data/docs.json` — see the write-docs skill.
|
||||
@@ -5,9 +5,14 @@
|
||||
// - redirect destinations in docs/astro.config.mjs
|
||||
// - href string literals in docs .astro components
|
||||
// - docs paths linked from the demo site: <DocsLink path="…"> and getDocsUrl('…')
|
||||
// - asset paths that actually render: src, poster and CSS url() in mdx and in
|
||||
// docs .astro components
|
||||
// Anchors are checked against heading slugs computed with github-slugger —
|
||||
// the same library the markdown pipeline uses. Demo markup inside <Example>
|
||||
// blocks and code fences is ignored; its links are illustrative by design.
|
||||
// Assets are the exception: an <img> inside an <Example> really renders on the
|
||||
// page, so those are checked. Code fences stay exempt — a snippet points at
|
||||
// files in the reader's own project (/media/clip.mp4), not at ours.
|
||||
// Run: pnpm run check-docs-links
|
||||
|
||||
import { existsSync, readFileSync } from 'node:fs'
|
||||
@@ -66,10 +71,10 @@ for (const match of astroConfig.matchAll(/\['([a-z-]+)',\s*'([a-z-]+)'\]/g)) {
|
||||
const assetRoots: Record<string, string[]> = {
|
||||
'/img': [join(repoRoot, 'docs', 'assets', 'img')],
|
||||
'/static': [join(repoRoot, 'shared', 'static')],
|
||||
'/css': [join(repoRoot, 'docs', 'assets', 'css')],
|
||||
}
|
||||
// Built artifacts of other packages — not resolvable without a build.
|
||||
const skipPrefixes = ['/dist/', '/preview/', '/_vercel/', '/_astro/']
|
||||
// Built artifacts — not resolvable without a build. /css/ is compiled from
|
||||
// docs/scss/ into tmp-assets/css (see the docs `css` script).
|
||||
const skipPrefixes = ['/dist/', '/preview/', '/css/', '/_vercel/', '/_astro/']
|
||||
// Element ids rendered by DocsLayout, valid as anchors on every page.
|
||||
const layoutIds = new Set(['content', 'related', 'docsearch', 'menu', 'toc'])
|
||||
|
||||
@@ -106,12 +111,12 @@ const frontmatter = (file: string): string => {
|
||||
return source.startsWith('---') ? (source.split(/^---$/m, 3)[1] ?? '') : ''
|
||||
}
|
||||
|
||||
const stripCode = (text: string): string => text.replace(/^```[\s\S]*?^```/gm, '').replace(/`[^`\n]*`/g, '')
|
||||
|
||||
const stripDemosAndCode = (text: string): string =>
|
||||
text
|
||||
stripCode(text)
|
||||
.replace(/<Example\b[\s\S]*?<\/Example>/g, '')
|
||||
.replace(/<Example\b[^>]*\/>/g, '')
|
||||
.replace(/^```[\s\S]*?^```/gm, '')
|
||||
.replace(/`[^`\n]*`/g, '')
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Validation
|
||||
@@ -164,6 +169,28 @@ const checkTarget = (sourceLabel: string, link: string, sourceFile?: string) =>
|
||||
}
|
||||
}
|
||||
|
||||
// Asset references that the browser really fetches: src, poster and CSS url().
|
||||
// Only literal absolute paths are checked — `src={...}` is built at render time
|
||||
// and cannot be resolved here.
|
||||
const assetRefPattern = /(?:src|poster)="(\/[^"]+)"|url\((\/[^)"']+)\)/g
|
||||
|
||||
const checkAsset = (sourceLabel: string, reference: string) => {
|
||||
checkedLinks++
|
||||
const path = (reference.split(/[?#]/)[0] ?? '').replace(/\/+$/, '')
|
||||
if (skipPrefixes.some((prefix) => path.startsWith(prefix))) return
|
||||
|
||||
const assetRoot = Object.keys(assetRoots).find((prefix) => path.startsWith(`${prefix}/`))
|
||||
if (!assetRoot) {
|
||||
// Outside a known root the file cannot be resolved from the repo, so the
|
||||
// reference is only reportable when it claims a directory we do own.
|
||||
return
|
||||
}
|
||||
const roots = assetRoots[assetRoot] ?? []
|
||||
if (!roots.some((root) => existsSync(join(root, path.slice(assetRoot.length + 1))))) {
|
||||
errors.push(`${sourceLabel}: dead asset "${reference}"`)
|
||||
}
|
||||
}
|
||||
|
||||
// 1. Markdown links + `related:` frontmatter in every mdx page.
|
||||
for (const file of sync(join(contentDir, '**', '*.mdx'))) {
|
||||
const label = relative(repoRoot, file)
|
||||
@@ -179,6 +206,11 @@ for (const file of sync(join(contentDir, '**', '*.mdx'))) {
|
||||
checkTarget(label, link, file)
|
||||
}
|
||||
|
||||
// Assets render from demo markup too, so this uses the code-only stripper.
|
||||
for (const match of stripCode(body(file)).matchAll(assetRefPattern)) {
|
||||
checkAsset(label, match[1] ?? match[2] ?? '')
|
||||
}
|
||||
|
||||
// `related:` accepts both the array and the scalar form (see content.config.ts).
|
||||
const related = frontmatter(file).match(/^related:\s*(.+)$/m)
|
||||
if (related) {
|
||||
@@ -214,9 +246,13 @@ for (const destination of redirectDestinations) {
|
||||
// 4. Internal href literals in docs components, layouts and astro pages.
|
||||
for (const file of sync(join(repoRoot, 'docs', '{components,layouts,pages}', '**', '*.astro'))) {
|
||||
const label = relative(repoRoot, file)
|
||||
for (const match of readFileSync(file, 'utf8').matchAll(/href(?:=|:\s*)["'](\/[^"']*)["']/g)) {
|
||||
const source = readFileSync(file, 'utf8')
|
||||
for (const match of source.matchAll(/href(?:=|:\s*)["'](\/[^"']*)["']/g)) {
|
||||
checkTarget(label, match[1] ?? '')
|
||||
}
|
||||
for (const match of source.matchAll(assetRefPattern)) {
|
||||
checkAsset(label, match[1] ?? match[2] ?? '')
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Docs paths used by the demo site — <DocsLink path="…"> and getDocsUrl('…').
|
||||
@@ -234,9 +270,9 @@ for (const file of sync(join(repoRoot, '{preview,shared}', '**', '*.astro'), { i
|
||||
|
||||
const uniqueErrors = [...new Set(errors)]
|
||||
if (uniqueErrors.length > 0) {
|
||||
console.error(`Found ${uniqueErrors.length} dead link(s) (${checkedLinks} links checked):\n`)
|
||||
console.error(`Found ${uniqueErrors.length} dead reference(s) (${checkedLinks} links and assets checked):\n`)
|
||||
for (const error of uniqueErrors) console.error(` ${error}`)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
console.log(`OK — ${checkedLinks} links checked across ${routeFiles.size} pages, no dead links.`)
|
||||
console.log(`OK — ${checkedLinks} links and assets checked across ${routeFiles.size} pages, nothing dead.`)
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { readFileSync, writeFileSync } from 'node:fs'
|
||||
import { join, dirname } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { sync } from 'glob'
|
||||
import * as prettier from 'prettier'
|
||||
import { compile } from '@mdx-js/mdx'
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
const docs: string[] = sync(join(__dirname, '..', 'docs', 'content', '**', '*.mdx'))
|
||||
|
||||
// Finding nothing means the docs moved and this glob was not updated. Exiting 0
|
||||
// with no output would look like "everything is already formatted".
|
||||
if (docs.length === 0) {
|
||||
console.error('No docs pages found — check the glob in this script.')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
async function formatHTML(htmlString: string, options: prettier.Options = {}): Promise<string> {
|
||||
try {
|
||||
const formattedHtml = await prettier.format(htmlString, {
|
||||
parser: 'html',
|
||||
printWidth: 100,
|
||||
...options,
|
||||
})
|
||||
return formattedHtml
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
console.error('Error formatting HTML:', errorMessage)
|
||||
return htmlString // Return original in case of an error
|
||||
}
|
||||
}
|
||||
|
||||
async function replaceAsync(str: string, regex: RegExp, asyncFn: (...args: string[]) => Promise<string>): Promise<string> {
|
||||
const matches = [...str.matchAll(regex)]
|
||||
|
||||
const replacements = await Promise.all(matches.map(async (match: RegExpMatchArray) => asyncFn(...(match as unknown as string[]))))
|
||||
|
||||
// Splice by match index. A string `.replace()` would hit the first occurrence
|
||||
// every time, so two identical examples in one file would rewrite the same
|
||||
// spot twice and leave the other untouched.
|
||||
let result = ''
|
||||
let last = 0
|
||||
matches.forEach((match: RegExpMatchArray, i: number) => {
|
||||
const start = match.index ?? 0
|
||||
result += str.slice(last, start) + replacements[i]
|
||||
last = start + match[0].length
|
||||
})
|
||||
|
||||
return result + str.slice(last)
|
||||
}
|
||||
|
||||
/**
|
||||
* `<Example>` slots hold the demo markup, so they get the same treatment as an
|
||||
* ```html fence.
|
||||
*
|
||||
* Slots containing `{` are skipped. In MDX every unescaped brace is a JSX
|
||||
* expression — a component prop (`title={…}`), or the template literal that
|
||||
* `<script>` and `<style>` demos are wrapped in so their JS/CSS braces survive.
|
||||
* The html parser either throws on those ("Opening tag not terminated") or
|
||||
* reformats the embedded code and breaks the expression. Embedded formatting is
|
||||
* off as a second guard.
|
||||
*
|
||||
* Empty lines are stripped: a blank line inside the slot would make MDX start a
|
||||
* new paragraph. Raw text is glued to the preceding markup line: markdown
|
||||
* syntax is line-based, so a text line of its own can turn into a heading
|
||||
* (`=`), a list (`+ 2`) or a blockquote (`>`); glued after a tag it stays
|
||||
* phrasing text, and the docs pipeline unwraps the paragraph MDX wraps it in
|
||||
* (docs/lib/satteri-unwrap-jsx-paragraphs.mjs).
|
||||
*
|
||||
* The real MDX compiler has the final word: an example whose formatted form
|
||||
* it rejects keeps its original form.
|
||||
*/
|
||||
async function formatExamples(source: string): Promise<string> {
|
||||
return replaceAsync(source, /(<Example\b[^>]*>\n)([\s\S]*?)(\n<\/Example>)/g, async (_m: string, open: string, inner: string, close: string) => {
|
||||
if (inner.includes('{')) return _m
|
||||
|
||||
// Whitespace sensitivity is off: MDX drops whitespace between sibling JSX
|
||||
// elements anyway, and with the default `css` sensitivity prettier glues
|
||||
// inline siblings together (`</span><span`) and wraps inside their tags.
|
||||
const formatted = glueTextLines((await formatHTML(inner, { embeddedLanguageFormatting: 'off', htmlWhitespaceSensitivity: 'ignore' })).replace(/^\s*[\r\n]/gm, '').trim())
|
||||
if (!formatted) return _m
|
||||
|
||||
if (!(await compilesAsMdx(open + formatted + close))) {
|
||||
console.warn(`Left one example as-is (MDX cannot parse the formatted form)`)
|
||||
return _m
|
||||
}
|
||||
|
||||
return open + formatted + close
|
||||
})
|
||||
}
|
||||
|
||||
async function compilesAsMdx(source: string): Promise<boolean> {
|
||||
try {
|
||||
await compile(source)
|
||||
return true
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// A complete tag; character classes also match newlines, so a tag spread over
|
||||
// several lines (one attribute per line) matches too.
|
||||
const tagPattern = /<\/?[a-zA-Z][\w.-]*(?:"[^"]*"|'[^']*'|[^<>"'])*?\/?>/g
|
||||
const voidTags = new Set(['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr'])
|
||||
|
||||
/** opens minus closes over the tags of one line */
|
||||
function lineBalance(line: string): number {
|
||||
let depth = 0
|
||||
for (const m of line.matchAll(/<(\/)?([a-zA-Z][\w.-]*)((?:"[^"]*"|'[^']*'|[^<>"'])*?)(\/)?>/g)) {
|
||||
if (m[1]) depth--
|
||||
else if (!m[4] && !voidTags.has(m[2]!.toLowerCase())) depth++
|
||||
}
|
||||
return depth
|
||||
}
|
||||
|
||||
const hasText = (line: string): boolean => line.replace(/<[^<>]*>/g, '').trim().length > 0
|
||||
|
||||
/** The tags of a fragment in order, for comparing markup before and after formatting. */
|
||||
const tagSequence = (html: string): string => [...html.matchAll(/<(\/?)([a-zA-Z][\w.-]*)/g)].map((m) => `${m[1]}${m[2]!.toLowerCase()}`).join(',')
|
||||
|
||||
/**
|
||||
* Merge raw-text lines back into their markup (see formatExamples). MDX parses
|
||||
* a line that mixes text and tags as one markdown paragraph, and every tag in
|
||||
* it must open and close within that paragraph — so a text line joins the
|
||||
* preceding line, and the joined line keeps absorbing following lines until
|
||||
* its tags balance. Tags spread over several lines are folded up first so the
|
||||
* balance is countable per line; examples without raw text keep prettier's
|
||||
* output untouched.
|
||||
*/
|
||||
function glueTextLines(formatted: string): string {
|
||||
const lines = formatted.split('\n')
|
||||
if (!lines.some((line) => hasText(line))) return formatted
|
||||
|
||||
const out: string[] = []
|
||||
for (const line of formatted.replace(tagPattern, (tag) => tag.replace(/\s+/g, ' ').replace(/ >$/, '>')).split('\n')) {
|
||||
const trimmed = line.trim()
|
||||
const tail = out[out.length - 1]
|
||||
const absorbing = tail !== undefined && hasText(tail) && lineBalance(tail) > 0
|
||||
if (tail !== undefined && trimmed && (absorbing || !trimmed.startsWith('<'))) out[out.length - 1] = `${tail} ${trimmed}`
|
||||
else out.push(line)
|
||||
// A text line can also land after a closing tag whose opener sits on an
|
||||
// earlier line (label after a multi-line svg) — pull those lines up too.
|
||||
while (out.length > 1 && hasText(out[out.length - 1]!) && lineBalance(out[out.length - 1]!) < 0) {
|
||||
const merged = `${out[out.length - 2]} ${out[out.length - 1]!.trim()}`
|
||||
out.splice(out.length - 2, 2, merged)
|
||||
}
|
||||
}
|
||||
return out.join('\n')
|
||||
}
|
||||
|
||||
async function processFiles(): Promise<void> {
|
||||
for (const file of docs) {
|
||||
const oldContent = readFileSync(file, 'utf8')
|
||||
|
||||
// Code fences, anchored to column 0: an indented fence belongs to a list
|
||||
// item, and reprinting it without that indentation breaks the list.
|
||||
let content = await replaceAsync(oldContent, /^(```([a-z0-9]+).*?\n)([\s\S]*?)^(```)/gm, async (m: string, m1: string, m2: string, m3: string, m4: string) => {
|
||||
if (m2 === 'html') {
|
||||
let formattedHtml = await formatHTML(m3)
|
||||
|
||||
// remove empty lines
|
||||
formattedHtml = formattedHtml.replace(/^\s*[\r\n]/gm, '')
|
||||
|
||||
// Fences hold illustrative snippets, not always whole documents, and
|
||||
// js-beautify silently closes what it thinks is unclosed. Only take
|
||||
// its output when it rewrapped the same tags it was given.
|
||||
if (tagSequence(formattedHtml) !== tagSequence(m3)) return m
|
||||
|
||||
return m1 + formattedHtml.trim() + '\n' + m4
|
||||
}
|
||||
return m.trim()
|
||||
})
|
||||
|
||||
content = await formatExamples(content)
|
||||
|
||||
if (content !== oldContent) {
|
||||
writeFileSync(file, content, 'utf8')
|
||||
console.log(`Reformatted ${file}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processFiles().catch((error) => {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
console.error('Error processing files:', errorMessage)
|
||||
process.exit(1)
|
||||
})
|
||||
@@ -1,124 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { readFileSync, writeFileSync } from 'node:fs'
|
||||
import { join, dirname } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { sync } from 'glob'
|
||||
import * as prettier from 'prettier'
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
const docs: string[] = sync(join(__dirname, '..', 'docs', 'content', '**', '*.mdx'))
|
||||
|
||||
// Finding nothing means the docs moved and this glob was not updated. Exiting 0
|
||||
// with no output would look like "everything is already formatted".
|
||||
if (docs.length === 0) {
|
||||
console.error('No docs pages found — check the glob in this script.')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
async function formatHTML(htmlString: string, options: prettier.Options = {}): Promise<string> {
|
||||
try {
|
||||
const formattedHtml = await prettier.format(htmlString, {
|
||||
parser: 'html',
|
||||
printWidth: 100,
|
||||
...options,
|
||||
})
|
||||
return formattedHtml
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
console.error('Error formatting HTML:', errorMessage)
|
||||
return htmlString // Return original in case of an error
|
||||
}
|
||||
}
|
||||
|
||||
async function replaceAsync(str: string, regex: RegExp, asyncFn: (...args: string[]) => Promise<string>): Promise<string> {
|
||||
const matches = [...str.matchAll(regex)]
|
||||
|
||||
const replacements = await Promise.all(matches.map(async (match: RegExpMatchArray) => asyncFn(...(match as unknown as string[]))))
|
||||
|
||||
// Splice by match index. A string `.replace()` would hit the first occurrence
|
||||
// every time, so two identical examples in one file would rewrite the same
|
||||
// spot twice and leave the other untouched.
|
||||
let result = ''
|
||||
let last = 0
|
||||
matches.forEach((match: RegExpMatchArray, i: number) => {
|
||||
const start = match.index ?? 0
|
||||
result += str.slice(last, start) + replacements[i]
|
||||
last = start + match[0].length
|
||||
})
|
||||
|
||||
return result + str.slice(last)
|
||||
}
|
||||
|
||||
/**
|
||||
* `<Example>` slots hold the demo markup, so they get the same treatment as an
|
||||
* ```html fence.
|
||||
*
|
||||
* Slots containing `{` are skipped. In MDX every unescaped brace is a JSX
|
||||
* expression — a component prop (`title={…}`), or the template literal that
|
||||
* `<script>` and `<style>` demos are wrapped in so their JS/CSS braces survive.
|
||||
* The html parser either throws on those ("Opening tag not terminated") or
|
||||
* reformats the embedded code and breaks the expression. Embedded formatting is
|
||||
* off as a second guard.
|
||||
*
|
||||
* Empty lines are stripped: a blank line inside the slot would make MDX start a
|
||||
* new paragraph and wrap the demo markup in a stray `<p>`.
|
||||
*/
|
||||
async function formatExamples(source: string): Promise<string> {
|
||||
return replaceAsync(source, /(<Example\b[^>]*>\n)([\s\S]*?)(\n<\/Example>)/g, async (_m: string, open: string, inner: string, close: string) => {
|
||||
// A space between two tags on one line is rendered, but JSX drops whitespace
|
||||
// that contains a newline. Reflowing such an example would silently delete the
|
||||
// gaps between, say, a row of buttons, so it is left alone.
|
||||
if (inner.includes('{') || />[ \t]+</.test(inner)) return _m
|
||||
|
||||
// A line that does not start with a tag is markdown flow content: MDX renders
|
||||
// it as its own <p>. Reflowing would fold it into a tag line and drop the
|
||||
// paragraph, so those examples are left alone too.
|
||||
const lines = inner.split('\n').filter((line) => line.trim())
|
||||
if (!lines.every((line) => line.trim().startsWith('<'))) return _m
|
||||
|
||||
const formatted = (await formatHTML(inner, { embeddedLanguageFormatting: 'off' })).replace(/^\s*[\r\n]/gm, '').trim()
|
||||
|
||||
// Only take the result when every line starts with a tag. MDX parses the slot
|
||||
// as markdown flow content, so a line starting with anything else changes what
|
||||
// is rendered: text becomes a stray <p>, and prettier's inline-close artifact
|
||||
// (`</a` then a lone `>`) is not valid JSX at all. Where prettier cannot format
|
||||
// without breaking inline content, the example is left exactly as it was.
|
||||
const isSafe = formatted.split('\n').every((line) => line.trim().startsWith('<'))
|
||||
|
||||
return formatted && isSafe ? open + formatted + close : _m
|
||||
})
|
||||
}
|
||||
|
||||
async function processFiles(): Promise<void> {
|
||||
for (const file of docs) {
|
||||
const oldContent = readFileSync(file, 'utf8')
|
||||
|
||||
// get codeblocks from markdown
|
||||
let content = await replaceAsync(oldContent, /(```([a-z0-9]+).*?\n)(.*?)(```)/gs, async (m: string, m1: string, m2: string, m3: string, m4: string) => {
|
||||
if (m2 === 'html') {
|
||||
let formattedHtml = await formatHTML(m3)
|
||||
|
||||
// remove empty lines
|
||||
formattedHtml = formattedHtml.replace(/^\s*[\r\n]/gm, '')
|
||||
|
||||
return m1 + formattedHtml.trim() + '\n' + m4
|
||||
}
|
||||
return m.trim()
|
||||
})
|
||||
|
||||
content = await formatExamples(content)
|
||||
|
||||
if (content !== oldContent) {
|
||||
writeFileSync(file, content, 'utf8')
|
||||
console.log(`Reformatted ${file}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processFiles().catch((error) => {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
console.error('Error processing files:', errorMessage)
|
||||
process.exit(1)
|
||||
})
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/docs": minor
|
||||
---
|
||||
|
||||
Added an Accessibility section to every UI documentation page.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/docs": patch
|
||||
---
|
||||
|
||||
Documented card status, progress, actions, subtitle, surfaces, scrollable body, tables, links and overlays.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/docs": minor
|
||||
---
|
||||
|
||||
Added installation and usage sections to the chart and countup pages, covering the `.chart-*` size classes and sparklines.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/docs": minor
|
||||
---
|
||||
|
||||
Added a class reference table to every component page, from the new `classnames` front matter.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/docs": patch
|
||||
---
|
||||
|
||||
Fixed highlighted code blocks using hardcoded colors instead of the Tabler surface tokens.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/docs": patch
|
||||
---
|
||||
|
||||
Fixed the copy button in docs examples to be a `button` with an accessible name.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/docs": patch
|
||||
---
|
||||
|
||||
Fixed docs example code blocks gluing inline elements like `<label>` and `<input>` onto one line.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/docs": patch
|
||||
---
|
||||
|
||||
Added a `dark` background option to the docs `<Example>` component.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/docs": patch
|
||||
---
|
||||
|
||||
Updated docs examples to use the `<Icon />` component and consistent Prettier formatting.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/docs": patch
|
||||
---
|
||||
|
||||
Fixed keyboard access in docs examples for carousel controls, disabled links, `btn-loading` and progress bars.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/docs": patch
|
||||
---
|
||||
|
||||
Fixed install snippets pointing at urls that do not resolve on the vector map, inline player and icon pages.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/docs": patch
|
||||
---
|
||||
|
||||
Fixed docs examples using classes that do not exist, such as `alert-facebook`, `btn-close-white`, `bg-gray` and `btn-xs`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/docs": patch
|
||||
---
|
||||
|
||||
Added tooltips and accessible names to the footer icon links.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/docs": patch
|
||||
---
|
||||
|
||||
Stacked form docs examples in a column and tightened the sidebar nested menu indent.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/docs": patch
|
||||
---
|
||||
|
||||
Moved the form pages backed by a third-party library into the Plugins section.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/docs": patch
|
||||
---
|
||||
|
||||
Renamed form docs pages without the `form-` prefix and flattened the Illustrations and Emails sections.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/docs": minor
|
||||
---
|
||||
|
||||
Updated the docs layout: elevated article panel, rounded sidebar navigation, "On this page" rail and restyled prev/next links.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/docs": minor
|
||||
---
|
||||
|
||||
Listed every component class in `llms.txt`, from the `classnames` front matter.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/docs": patch
|
||||
---
|
||||
|
||||
Split the getting started menu group into Getting started and Resources.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/docs": patch
|
||||
---
|
||||
|
||||
Updated the docs navbar to use `container-lg`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/docs": minor
|
||||
---
|
||||
|
||||
Added a source link and a copy-as-markdown button, and moved the class reference to the end of the page.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/docs": minor
|
||||
---
|
||||
|
||||
Added `classnames` to the social icons and flags pages.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/docs": minor
|
||||
---
|
||||
|
||||
Rewrote the autosize, range slider, WYSIWYG and dropzone plugin pages with installation, usage and accessibility sections.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/docs": patch
|
||||
---
|
||||
|
||||
Moved components that need a third-party library into the Plugins section.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/docs": patch
|
||||
---
|
||||
|
||||
Moved the Website, Preview and Support links from the docs sidebar to the top navbar.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/docs": patch
|
||||
---
|
||||
|
||||
Restyled the related and prev/next cards, and moved prev/next below the article panel.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/docs": patch
|
||||
---
|
||||
|
||||
Restored the `docs.scss` source for the docs styles, compiled with Sass instead of a checked-in `docs.css`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/docs": patch
|
||||
---
|
||||
|
||||
Fixed the search modal using the Algolia palette instead of Tabler colors, including an unreadable selected result.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/docs": patch
|
||||
---
|
||||
|
||||
Darkened the docs sidebar links, kept rows to one line and added a visible focus ring.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/docs": patch
|
||||
---
|
||||
|
||||
Fixed docs examples using class names that no longer exist, such as `alert-title` and `hr-text-center`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/docs": patch
|
||||
---
|
||||
|
||||
Documented sortable headers, selectable rows, stacked mobile tables, and outline, dot and icon-only badges.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/docs": minor
|
||||
---
|
||||
|
||||
Expanded the social icons, payments, vector map, inline player, PDF, EPS, illustrations preview and references pages.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/docs": patch
|
||||
---
|
||||
|
||||
Rewrote the timeline and datagrid pages with markup, variants and accessibility notes.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/docs": minor
|
||||
---
|
||||
|
||||
Documented `avatar-square`, `mention`, `offcanvas-narrow`, `btn-floating`, `card-cover`, `td-truncate` and other variants.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/docs": patch
|
||||
---
|
||||
|
||||
Fixed plugin demos showing their stock styles, because library CSS loaded after `tabler-vendors.css`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/core": patch
|
||||
---
|
||||
|
||||
Fixed the markdown table header keeping its surface background instead of going transparent.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/core": patch
|
||||
---
|
||||
|
||||
Fixed `offcanvas-narrow`, which had no effect on the width of the panel.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/preview": patch
|
||||
---
|
||||
|
||||
Removed the non-existent `mt` class from the placeholder card.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/core": patch
|
||||
---
|
||||
|
||||
Fixed the avatar corner radius inside `.form-imagecheck-image` and set `.nav` font size to the body font size.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/docs": minor
|
||||
---
|
||||
|
||||
Removed the EPS icons page, since `@tabler/icons-eps` is no longer maintained.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/core": minor
|
||||
---
|
||||
|
||||
Changed the default theme of `tabler-theme.js` to `auto`, following the system color scheme.
|
||||
@@ -11,6 +11,7 @@ packages-zip
|
||||
preview/public
|
||||
preview/tmp-assets
|
||||
docs/public
|
||||
docs/tmp-assets
|
||||
|
||||
# prettier-plugin-astro cannot parse HTML comments or <script> tags inside
|
||||
# JSX expressions ({cond && (<Fragment><!-- ... --><script>...)}) — these files
|
||||
|
||||
@@ -12,7 +12,7 @@ interface ThemeConfig {
|
||||
}
|
||||
|
||||
const themeConfig: ThemeConfig = {
|
||||
'theme': 'light',
|
||||
'theme': 'auto',
|
||||
'theme-base': 'gray',
|
||||
'theme-font': 'sans-serif',
|
||||
'theme-primary': 'blue',
|
||||
@@ -49,7 +49,8 @@ for (const key in themeConfig) {
|
||||
}
|
||||
|
||||
prefersDark.addEventListener('change', (event) => {
|
||||
if (localStorage.getItem('tabler-theme') === 'auto') {
|
||||
// No stored choice means the default, which is auto.
|
||||
if ((localStorage.getItem('tabler-theme') ?? 'auto') === 'auto') {
|
||||
if (event.matches) {
|
||||
document.documentElement.setAttribute('data-bs-theme', 'dark')
|
||||
} else {
|
||||
|
||||
+20
-1
@@ -55,7 +55,26 @@
|
||||
// Markdown tables pick up the styled table look (from `ui/_markdown.scss`)
|
||||
.prose > table,
|
||||
.markdown > table {
|
||||
@extend .table, .table-bordered, .table-sm;
|
||||
@extend .table;
|
||||
font-size: var(--body-font-size);
|
||||
|
||||
th:first-child,
|
||||
td:first-child {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
th:last-child,
|
||||
td:last-child {
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
tr:last-child > * {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
th {
|
||||
--bg-surface-tertiary: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
// Light-scoped subtrees inside a dark body inherit the dark styles
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
--nav-vertical-nested-padding-start: #{$nav-vertical-nested-padding-start};
|
||||
--nav-link-toggle-padding-x: #{$nav-link-toggle-padding-x};
|
||||
--nav-link-icon-margin-end: #{$nav-link-icon-margin-end};
|
||||
font-size: var(--body-font-size);
|
||||
}
|
||||
|
||||
.nav-vertical {
|
||||
|
||||
@@ -24,6 +24,5 @@
|
||||
|
||||
.offcanvas-narrow {
|
||||
--offcanvas-narrow-width: #{$offcanvas-narrow-width};
|
||||
|
||||
width: var(--offcanvas-narrow-width);
|
||||
--offcanvas-width: var(--offcanvas-narrow-width);
|
||||
}
|
||||
|
||||
@@ -91,6 +91,10 @@ blockquote {
|
||||
|
||||
p {
|
||||
margin-bottom: var(--blockquote-paragraph-margin-bottom);
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
cite {
|
||||
|
||||
@@ -92,6 +92,10 @@ Image check
|
||||
.form-imagecheck-input:checked ~ .form-imagecheck-figure & {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
border-radius: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
.form-imagecheck-caption {
|
||||
|
||||
@@ -3,6 +3,9 @@ dist/
|
||||
|
||||
public/
|
||||
|
||||
# temporary css build assets
|
||||
tmp-assets/
|
||||
|
||||
# generated types
|
||||
.astro/
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
|
Before Width: | Height: | Size: 25 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 24 KiB |
+45
-4
@@ -3,6 +3,7 @@ import { defineConfig, envField } from 'astro/config'
|
||||
import vercel from '@astrojs/vercel'
|
||||
import mdx from '@astrojs/mdx'
|
||||
import { satteri } from '@astrojs/markdown-satteri'
|
||||
import { unwrapJsxParagraphs } from './lib/satteri-unwrap-jsx-paragraphs.mjs'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { copyAssets } from '../.build/copy-assets'
|
||||
|
||||
@@ -34,6 +35,8 @@ export default defineConfig({
|
||||
// Google index, Algolia search results and external backlinks.
|
||||
redirects: {
|
||||
'/ui/base/markdown': { status: 301, destination: '/ui/base/prose' },
|
||||
// @tabler/icons-eps is no longer maintained; PDF is the vector format to use.
|
||||
'/icons/static-files/eps': { status: 301, destination: '/icons/static-files/pdf' },
|
||||
...Object.fromEntries(
|
||||
[
|
||||
['alerts', 'alert'],
|
||||
@@ -41,7 +44,6 @@ export default defineConfig({
|
||||
['badges', 'badge'],
|
||||
['buttons', 'button'],
|
||||
['cards', 'card'],
|
||||
['charts', 'chart'],
|
||||
['dropdowns', 'dropdown'],
|
||||
['icons', 'icon'],
|
||||
['modals', 'modal'],
|
||||
@@ -54,9 +56,36 @@ export default defineConfig({
|
||||
['timelines', 'timeline'],
|
||||
['toasts', 'toast'],
|
||||
['tooltips', 'tooltip'],
|
||||
['vector-maps', 'vector-map'],
|
||||
].map(([from, to]) => [`/ui/components/${from}`, { status: 301, destination: `/ui/components/${to}` }]),
|
||||
),
|
||||
// Components that need a third-party library moved to /ui/plugins/.
|
||||
...Object.fromEntries(['autosize', 'chart', 'countup', 'dropzone', 'fullcalendar', 'inline-player', 'lightbox', 'range-slider', 'signature', 'vector-map', 'wysiwyg'].map((slug) => [`/ui/components/${slug}`, { status: 301, destination: `/ui/plugins/${slug}` }])),
|
||||
// Pre-Astro plural urls for two of those pages, sent straight to the new home.
|
||||
'/ui/components/charts': { status: 301, destination: '/ui/plugins/chart' },
|
||||
'/ui/components/vector-maps': { status: 301, destination: '/ui/plugins/vector-map' },
|
||||
// The form- prefix was redundant inside /ui/forms/.
|
||||
'/ui/forms/form-elements': { status: 301, destination: '/ui/forms/elements' },
|
||||
'/ui/forms/form-fieldset': { status: 301, destination: '/ui/forms/fieldset' },
|
||||
'/ui/forms/form-floating': { status: 301, destination: '/ui/forms/floating-labels' },
|
||||
'/ui/forms/form-helpers': { status: 301, destination: '/ui/forms/helpers' },
|
||||
'/ui/forms/form-selectboxes': { status: 301, destination: '/ui/forms/select-group' },
|
||||
'/ui/forms/form-image-check': { status: 301, destination: '/ui/forms/image-check' },
|
||||
'/ui/forms/form-color-check': { status: 301, destination: '/ui/forms/color-check' },
|
||||
'/ui/forms/form-select-tomselect': { status: 301, destination: '/ui/plugins/advanced-select' },
|
||||
'/ui/forms/form-colorpicker': { status: 301, destination: '/ui/plugins/color-picker' },
|
||||
'/ui/forms/form-datepicker': { status: 301, destination: '/ui/plugins/date-picker' },
|
||||
'/ui/forms/form-input-mask': { status: 301, destination: '/ui/plugins/input-mask' },
|
||||
'/ui/forms/form-validation': { status: 301, destination: '/ui/forms/validation' },
|
||||
// Illustrations and Emails lost their "introduction" wrapper.
|
||||
'/illustrations/introduction': { status: 301, destination: '/illustrations' },
|
||||
'/illustrations/introduction/preview': { status: 301, destination: '/illustrations/preview' },
|
||||
'/illustrations/introduction/contents': { status: 301, destination: '/illustrations/contents' },
|
||||
'/illustrations/introduction/customization': { status: 301, destination: '/illustrations/customization' },
|
||||
'/illustrations/introduction/license': { status: 301, destination: '/illustrations/license' },
|
||||
'/emails/introduction': { status: 301, destination: '/emails' },
|
||||
'/emails/introduction/contents': { status: 301, destination: '/emails/contents' },
|
||||
'/emails/introduction/compiled-html': { status: 301, destination: '/emails/compiled-html' },
|
||||
'/emails/introduction/source-html': { status: 301, destination: '/emails/source-html' },
|
||||
},
|
||||
// pages live at the package root (./pages) — content-first layout; all
|
||||
// components/lib/data are shared (see the @shared alias). The docs content
|
||||
@@ -96,7 +125,16 @@ export default defineConfig({
|
||||
from: path('./assets'),
|
||||
to: path('./public'),
|
||||
label: '@tabler/docs',
|
||||
requiredFile: path('./assets/css/docs.css'),
|
||||
requiredFile: path('./assets/favicon.ico'),
|
||||
},
|
||||
{
|
||||
// docs css built by this package's sass pipeline (see the `css` script).
|
||||
// Source is tmp-assets/ (not dist/) for the same unbounded-growth reason
|
||||
// as in preview — see preview/.build/vite.config.mts.
|
||||
from: path('./tmp-assets/css'),
|
||||
to: path('./public/css'),
|
||||
label: '@tabler/docs',
|
||||
requiredFile: path('./tmp-assets/css/docs.css'),
|
||||
},
|
||||
{
|
||||
from: path('../core/dist'),
|
||||
@@ -126,12 +164,15 @@ export default defineConfig({
|
||||
{ from: path('./assets'), to: path('./public') },
|
||||
{ from: path('../shared/static'), to: path('./public/static') },
|
||||
],
|
||||
// watch-css writes straight into public/css — the file is already in
|
||||
// place, but Astro does not reload the browser on public/ changes.
|
||||
reloadDirs: [path('./public/css')],
|
||||
}),
|
||||
mdx(),
|
||||
],
|
||||
markdown: {
|
||||
// No typographic quote rewriting.
|
||||
processor: satteri({ features: { smartPunctuation: false } }),
|
||||
processor: satteri({ features: { smartPunctuation: false }, mdastPlugins: [unwrapJsxParagraphs] }),
|
||||
shikiConfig: {
|
||||
theme: 'github-dark',
|
||||
},
|
||||
|
||||
@@ -16,9 +16,9 @@ const highlighted = await highlightCode(code, lang)
|
||||
---
|
||||
|
||||
<div class="position-relative">
|
||||
<a class="btn btn-icon btn-dark position-absolute m-2 top-0 end-0 z-3" data-clipboard-text={code}>
|
||||
<button type="button" class="btn btn-icon btn-dark position-absolute m-2 top-0 end-0 z-3" data-clipboard-text={code} aria-label="Copy code">
|
||||
<Icon name="clipboard" />
|
||||
<Icon name="check" class="d-none" />
|
||||
</a>
|
||||
</button>
|
||||
<Fragment set:html={highlighted} />
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
---
|
||||
// Class reference for a component, from the page's `classnames` front matter
|
||||
// (see docs/content.config.ts). Groups are rendered in a fixed order so every
|
||||
// page reads the same way, whatever order the front matter happens to use.
|
||||
import Badge from '@ui/Badge.astro'
|
||||
|
||||
type Entry = { class: string; desc: string; default: boolean }
|
||||
|
||||
interface Props {
|
||||
classnames: Record<string, Entry[]>
|
||||
}
|
||||
|
||||
const { classnames }: Props = Astro.props
|
||||
|
||||
const groupOrder = ['component', 'part', 'style', 'modifier', 'behavior', 'direction', 'color', 'size']
|
||||
|
||||
// One soft color per kind, so the type column can be scanned without reading it.
|
||||
// `bg-*-lt` carries both the tint and a matching text color, and follows the
|
||||
// color mode on its own.
|
||||
const groupColors: Record<string, string> = {
|
||||
component: 'blue',
|
||||
part: 'cyan',
|
||||
style: 'purple',
|
||||
modifier: 'indigo',
|
||||
behavior: 'yellow',
|
||||
direction: 'teal',
|
||||
color: 'pink',
|
||||
size: 'orange',
|
||||
}
|
||||
|
||||
const groupIcons: Record<string, string> = {
|
||||
component: 'box',
|
||||
part: 'puzzle',
|
||||
style: 'brush',
|
||||
modifier: 'adjustments',
|
||||
behavior: 'hand-click',
|
||||
direction: 'arrows-move',
|
||||
color: 'palette',
|
||||
size: 'ruler-measure',
|
||||
}
|
||||
const groups = Object.entries(classnames).sort(([a], [b]) => (groupOrder.indexOf(a) + 1 || 99) - (groupOrder.indexOf(b) + 1 || 99))
|
||||
---
|
||||
|
||||
<!-- BEGIN DOCS CLASSNAMES -->
|
||||
<h2 id="class-reference">Class reference</h2>
|
||||
|
||||
<p>Every class this component ships, grouped by what it changes. A name in braces stands for a family — <code>{'{color}'}</code> is any base color, <code>{'{breakpoint}'}</code> any responsive step.</p>
|
||||
|
||||
<table class="docs-classnames">
|
||||
<tbody>
|
||||
{
|
||||
groups.map(([group, entries]) =>
|
||||
entries.map((entry) => (
|
||||
<tr>
|
||||
<td>
|
||||
<code>{entry.class}</code>
|
||||
</td>
|
||||
<td>
|
||||
<Badge color={groupColors[group] ?? 'secondary'} light icon={groupIcons[group] ?? 'tag'} text={group} class="text-capitalize" />
|
||||
</td>
|
||||
<td>
|
||||
{entry.desc}
|
||||
{entry.default && <Badge color="blue" light text="default" class="ms-2" />}
|
||||
</td>
|
||||
</tr>
|
||||
)),
|
||||
)
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
<!-- END DOCS CLASSNAMES -->
|
||||
@@ -9,7 +9,10 @@ interface MenuLeaf {
|
||||
url: string
|
||||
}
|
||||
|
||||
interface MenuGroup extends MenuLeaf {
|
||||
interface MenuGroup {
|
||||
title: string
|
||||
/** omitted for groups that only label a set of pages, with no index page of their own */
|
||||
url?: string
|
||||
children?: MenuLeaf[]
|
||||
}
|
||||
|
||||
@@ -25,6 +28,15 @@ interface Props {
|
||||
|
||||
const { url } = Astro.props
|
||||
const menu = docs.menu as MenuSection[]
|
||||
|
||||
// Keep declarations above this line: a value between the interfaces stops
|
||||
// Astro's frontmatter scanner from picking up `Props`, leaving props untyped.
|
||||
|
||||
/** Collapse target: from the group's url, or from its title when it has none. */
|
||||
const groupId = (group: MenuGroup) =>
|
||||
`collapse-${slug(group.url ?? group.title)
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9-]+/g, '-')}`
|
||||
---
|
||||
|
||||
<!-- BEGIN DOCS MENU -->
|
||||
@@ -42,23 +54,28 @@ const menu = docs.menu as MenuSection[]
|
||||
const expanded = url === level2.url || Boolean(level2.children?.some((child) => child.url === url))
|
||||
return (
|
||||
<div>
|
||||
{/* href/data-bs-* only when the element has children */}
|
||||
{hasChildren ? (
|
||||
<a class={`nav-link${expanded ? ' active' : ''}`} href={level2.url} data-bs-toggle="collapse" data-bs-target={`#collapse-${slug(level2.url)}`} aria-expanded={expanded ? 'true' : 'false'}>
|
||||
{level2.title} <span class="nav-link-toggle" />
|
||||
{/* href/data-bs-* only when the element has children; a group
|
||||
without an index page toggles from a button instead */}
|
||||
{hasChildren && level2.url ? (
|
||||
<a class={`nav-link${expanded ? ' active' : ''}`} href={level2.url} data-bs-toggle="collapse" data-bs-target={`#${groupId(level2)}`} aria-expanded={expanded ? 'true' : 'false'} aria-current={url === level2.url ? 'page' : undefined}>
|
||||
<span class="nav-link-title">{level2.title}</span> <span class="nav-link-toggle" />
|
||||
</a>
|
||||
) : hasChildren ? (
|
||||
<button type="button" class="nav-link w-100 bg-transparent border-0 text-start" data-bs-toggle="collapse" data-bs-target={`#${groupId(level2)}`} aria-expanded={expanded ? 'true' : 'false'}>
|
||||
<span class="nav-link-title">{level2.title}</span> <span class="nav-link-toggle" />
|
||||
</button>
|
||||
) : (
|
||||
<a class={`nav-link${expanded ? ' active' : ''}`} href={level2.url}>
|
||||
{level2.title}
|
||||
<a class={`nav-link${expanded ? ' active' : ''}`} href={level2.url} aria-current={url === level2.url ? 'page' : undefined}>
|
||||
<span class="nav-link-title">{level2.title}</span>
|
||||
</a>
|
||||
)}
|
||||
|
||||
{hasChildren && (
|
||||
<div class={`nav nav-vertical collapse${expanded ? ' show' : ''}`} id={`collapse-${slug(level2.url)}`}>
|
||||
<div class={`nav nav-vertical collapse${expanded ? ' show' : ''}`} id={groupId(level2)}>
|
||||
{level2.children!.map((level3) => (
|
||||
<div>
|
||||
<a class={`nav-link${url === level3.url ? ' active' : ''}`} href={level3.url}>
|
||||
{level3.title}
|
||||
<a class={`nav-link${url === level3.url ? ' active' : ''}`} href={level3.url} aria-current={url === level3.url ? 'page' : undefined}>
|
||||
<span class="nav-link-title">{level3.title}</span>
|
||||
</a>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -1,151 +1,44 @@
|
||||
---
|
||||
import Icon from '@ui/Icon.astro'
|
||||
import DocsLogo from './DocsLogo.astro'
|
||||
import docs from '@data/docs.json'
|
||||
import { site } from '@shared/lib/site'
|
||||
|
||||
// Website / Preview / Support come from shared/data/docs.json, the same list the
|
||||
// sidebar used to render — keeping one source of truth for the product links.
|
||||
const productLinks = docs.links as { title: string; url: string; icon: string }[]
|
||||
|
||||
// Eventually belongs in src/lib/site.ts (out of scope for this task).
|
||||
const previewUrl = 'https://preview.tabler.io'
|
||||
const changelogUrl = 'https://tabler.io/changelog'
|
||||
---
|
||||
|
||||
<!-- BEGIN DOCS NAVBAR -->
|
||||
<nav class="navbar navbar-expand sticky-top" aria-label="Docs">
|
||||
<div class="container">
|
||||
<div class="row flex-fill align-items-md-center">
|
||||
<div class="col">
|
||||
<div class="d-flex align-items-center gap-4">
|
||||
<a href="/" class="navbar-brand navbar-brand-autodark gap-4">
|
||||
<DocsLogo />
|
||||
</a>
|
||||
<div>
|
||||
<span class="badge">v{site.version}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-none d-md-block col">
|
||||
{
|
||||
/* Native Tabler search input. The script below lazy-imports @docsearch/js on
|
||||
interaction and opens its modal; DocSearch mounts into the hidden #docsearch. */
|
||||
}
|
||||
<div class="input-icon">
|
||||
<span class="input-icon-addon">
|
||||
<Icon name="search" />
|
||||
</span>
|
||||
<input type="search" id="docs-search-input" class="form-control cursor-pointer" placeholder="Search…" aria-label="Search documentation" autocomplete="off" readonly />
|
||||
<span class="input-icon-addon">
|
||||
<kbd id="docs-search-kbd">⌘K</kbd>
|
||||
</span>
|
||||
</div>
|
||||
<div id="docsearch" class="d-none"></div>
|
||||
</div>
|
||||
<div class="col d-flex">
|
||||
<ul class="navbar-nav ms-auto gap-2 align-items-center">
|
||||
<li class="nav-item d-none d-md-block">
|
||||
<a href={previewUrl} class="nav-link">Preview</a>
|
||||
</li>
|
||||
<li class="nav-item d-none d-md-block">
|
||||
<a href={changelogUrl} class="nav-link">Changelog</a>
|
||||
</li>
|
||||
<li class="nav-item hide-theme-dark">
|
||||
<a href="?theme=dark" class="btn btn-icon">
|
||||
<Icon name="moon" />
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item hide-theme-light">
|
||||
<a href="?theme=light" class="btn btn-icon">
|
||||
<Icon name="sun" />
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href={site.githubUrl} class="btn btn-icon" target="_blank" rel="noopener noreferrer">
|
||||
<Icon name="brand-github" />
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href={previewUrl} class="btn btn-primary" target="_blank" rel="noopener noreferrer">
|
||||
<Icon name="eye" /> Preview
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="container-lg">
|
||||
<div class="d-flex align-items-center flex-fill gap-2">
|
||||
<button type="button" class="btn btn-icon btn-ghost-secondary d-lg-none" data-bs-toggle="offcanvas" data-bs-target="#docs-menu-offcanvas" aria-controls="docs-menu-offcanvas" aria-label="Open documentation menu">
|
||||
<Icon name="menu-2" />
|
||||
</button>
|
||||
<a href="/" class="navbar-brand navbar-brand-autodark me-2">
|
||||
<DocsLogo />
|
||||
</a>
|
||||
<span class="badge d-none d-sm-inline-block">v{site.version}</span>
|
||||
<div class="ms-auto d-flex align-items-center gap-2">
|
||||
<nav class="d-none d-md-flex align-items-center me-1" aria-label="Tabler sites">
|
||||
{
|
||||
productLinks.map((link) => (
|
||||
<a href={link.url} class="nav-link docs-navbar-link" target="_blank" rel="noopener noreferrer">
|
||||
{link.title}
|
||||
</a>
|
||||
))
|
||||
}
|
||||
<a href={changelogUrl} class="nav-link docs-navbar-link" target="_blank" rel="noopener noreferrer">Changelog</a>
|
||||
</nav>
|
||||
<a href={site.githubUrl} class="btn btn-icon btn-ghost-secondary" target="_blank" rel="noopener noreferrer" aria-label="Tabler on GitHub">
|
||||
<Icon name="brand-github" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<!-- END DOCS NAVBAR -->
|
||||
|
||||
<script>
|
||||
// Lazy DocSearch: the native input above triggers a dynamic import of
|
||||
// @docsearch/js, which Vite splits into its own hashed chunk — nothing is
|
||||
// downloaded until the first interaction. DocSearch mounts into the hidden
|
||||
// #docsearch container; opening the modal means clicking its hidden button.
|
||||
import { DOCSEARCH_APP_ID, DOCSEARCH_INDEX_NAME, DOCSEARCH_API_KEY } from 'astro:env/client'
|
||||
|
||||
const input = document.getElementById('docs-search-input')
|
||||
const mount = document.getElementById('docsearch')
|
||||
// Local consts so TypeScript narrows `string | undefined` inside the closures below.
|
||||
const appId = DOCSEARCH_APP_ID
|
||||
const indexName = DOCSEARCH_INDEX_NAME
|
||||
const apiKey = DOCSEARCH_API_KEY
|
||||
|
||||
if (input && !(appId && indexName && apiKey)) {
|
||||
// No Algolia env config (see .env.example) — hide the dead search input.
|
||||
input.closest<HTMLElement>('.input-icon')?.classList.add('d-none')
|
||||
console.warn('Docs search disabled: DOCSEARCH_* env variables are not set.')
|
||||
}
|
||||
|
||||
if (input && mount && appId && indexName && apiKey) {
|
||||
const isMac = /Mac|iPhone|iPad|iPod/.test(navigator.userAgent)
|
||||
const kbd = document.getElementById('docs-search-kbd')
|
||||
if (kbd && !isMac) kbd.textContent = 'Ctrl K'
|
||||
|
||||
let state: 'idle' | 'loading' | 'ready' = 'idle'
|
||||
let openWhenReady = false
|
||||
|
||||
const openModal = () => mount.querySelector<HTMLElement>('.DocSearch-Button')?.click()
|
||||
|
||||
const load = async (open: boolean) => {
|
||||
openWhenReady = openWhenReady || open
|
||||
if (state === 'ready') {
|
||||
if (open) openModal()
|
||||
return
|
||||
}
|
||||
if (state === 'loading') return
|
||||
state = 'loading'
|
||||
try {
|
||||
const { default: docsearch } = await import('@docsearch/js')
|
||||
docsearch({
|
||||
container: '#docsearch',
|
||||
appId,
|
||||
indexName,
|
||||
apiKey,
|
||||
})
|
||||
state = 'ready'
|
||||
// The bundle renders its (hidden) button and binds its own shortcuts.
|
||||
if (openWhenReady) openModal()
|
||||
} catch {
|
||||
state = 'idle'
|
||||
}
|
||||
}
|
||||
|
||||
input.addEventListener('click', () => {
|
||||
load(true)
|
||||
input.blur()
|
||||
})
|
||||
// Keyboard users: prefetch on focus, open on Enter or when they start typing.
|
||||
input.addEventListener('focus', () => load(false))
|
||||
input.addEventListener('keydown', (event) => {
|
||||
if (event.key === 'Enter' || event.key.length === 1) {
|
||||
event.preventDefault()
|
||||
load(true)
|
||||
input.blur()
|
||||
}
|
||||
})
|
||||
input.addEventListener('pointerenter', () => load(false))
|
||||
document.addEventListener('keydown', (event) => {
|
||||
if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === 'k' && state !== 'ready') {
|
||||
event.preventDefault()
|
||||
load(true)
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -19,9 +19,15 @@ interface MenuNode {
|
||||
interface Props {
|
||||
/** Page URL in the docs namespace (equivalent of page.url), e.g. "/ui/components/alert". */
|
||||
url: string
|
||||
/**
|
||||
* Which half to render. The child cards of an index page are content and stay
|
||||
* inside the article panel; the prev/next nav sits on the page canvas below
|
||||
* it. Omitted renders both.
|
||||
*/
|
||||
only?: 'children' | 'pagination'
|
||||
}
|
||||
|
||||
const { url } = Astro.props
|
||||
const { url, only } = Astro.props
|
||||
|
||||
const children = await getDocsChildren(url)
|
||||
|
||||
@@ -61,7 +67,7 @@ const { prev, next, found } = findPage(docs.menu as MenuNode[]) ?? {
|
||||
---
|
||||
|
||||
<!-- BEGIN DOCS PAGINATION -->{
|
||||
children.length > 0 && (
|
||||
only !== 'pagination' && children.length > 0 && (
|
||||
<div class="mt-6 pt-6">
|
||||
<div class="row row-deck row-cards">
|
||||
{children.map((child: DocsPage) => (
|
||||
@@ -73,41 +79,25 @@ const { prev, next, found } = findPage(docs.menu as MenuNode[]) ?? {
|
||||
}
|
||||
|
||||
{
|
||||
children.length === 0 && found && (
|
||||
<div class="mt-6 pt-6">
|
||||
<ul class="pagination">
|
||||
{prev && (
|
||||
<li class="page-item page-prev">
|
||||
<a class="page-link" href={prev.url}>
|
||||
<div class="row align-items-center">
|
||||
<div class="col-auto">
|
||||
<Icon name="chevron-left" />
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="page-item-subtitle">previous</div>
|
||||
<div class="page-item-title">{prev.title}</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
)}
|
||||
{next && (
|
||||
<li class="page-item page-next">
|
||||
<a class="page-link" href={next.url}>
|
||||
<div class="row align-items-center">
|
||||
<div class="col">
|
||||
<div class="page-item-subtitle">next</div>
|
||||
<div class="page-item-title">{next.title}</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<Icon name="chevron-right" />
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
only !== 'children' && children.length === 0 && found && (prev || next) && (
|
||||
<nav class="docs-pagination" aria-label="Pagination">
|
||||
{prev && (
|
||||
<a class="docs-pagination-link" href={prev.url} rel="prev">
|
||||
<span class="docs-pagination-label">
|
||||
<Icon name="chevron-left" /> Previous
|
||||
</span>
|
||||
<span class="docs-pagination-title">{prev.title}</span>
|
||||
</a>
|
||||
)}
|
||||
{next && (
|
||||
<a class="docs-pagination-link docs-pagination-next" href={next.url} rel="next">
|
||||
<span class="docs-pagination-label">
|
||||
Next <Icon name="chevron-right" />
|
||||
</span>
|
||||
<span class="docs-pagination-title">{next.title}</span>
|
||||
</a>
|
||||
)}
|
||||
</nav>
|
||||
)
|
||||
}
|
||||
<!-- END DOCS PAGINATION -->
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
---
|
||||
// Docs search: a native Tabler input that opens the DocSearch modal.
|
||||
// Lives in the sidebar, above the menu.
|
||||
import Icon from '@ui/Icon.astro'
|
||||
---
|
||||
|
||||
<!-- BEGIN DOCS SEARCH -->
|
||||
<div class="input-icon docs-search">
|
||||
<span class="input-icon-addon">
|
||||
<Icon name="search" />
|
||||
</span>
|
||||
<input type="search" id="docs-search-input" class="form-control cursor-pointer" placeholder="Search…" aria-label="Search documentation" autocomplete="off" readonly />
|
||||
<span class="input-icon-addon">
|
||||
<span id="docs-search-kbd" class="fs-4">⌘K</span>
|
||||
</span>
|
||||
</div>
|
||||
<div id="docsearch" class="d-none"></div>
|
||||
<!-- END DOCS SEARCH -->
|
||||
|
||||
<script>
|
||||
// Lazy DocSearch: the native input above triggers a dynamic import of
|
||||
// @docsearch/js, which Vite splits into its own hashed chunk — nothing is
|
||||
// downloaded until the first interaction. DocSearch mounts into the hidden
|
||||
// #docsearch container; opening the modal means clicking its hidden button.
|
||||
import { DOCSEARCH_APP_ID, DOCSEARCH_INDEX_NAME, DOCSEARCH_API_KEY } from 'astro:env/client'
|
||||
|
||||
const input = document.getElementById('docs-search-input')
|
||||
const mount = document.getElementById('docsearch')
|
||||
// Local consts so TypeScript narrows `string | undefined` inside the closures below.
|
||||
const appId = DOCSEARCH_APP_ID
|
||||
const indexName = DOCSEARCH_INDEX_NAME
|
||||
const apiKey = DOCSEARCH_API_KEY
|
||||
|
||||
if (input && !(appId && indexName && apiKey)) {
|
||||
// No Algolia env config (see .env.example) — hide the dead search input.
|
||||
input.closest<HTMLElement>('.input-icon')?.classList.add('d-none')
|
||||
console.warn('Docs search disabled: DOCSEARCH_* env variables are not set.')
|
||||
}
|
||||
|
||||
if (input && mount && appId && indexName && apiKey) {
|
||||
const isMac = /Mac|iPhone|iPad|iPod/.test(navigator.userAgent)
|
||||
const kbd = document.getElementById('docs-search-kbd')
|
||||
if (kbd && !isMac) kbd.textContent = 'Ctrl K'
|
||||
|
||||
let state: 'idle' | 'loading' | 'ready' = 'idle'
|
||||
let openWhenReady = false
|
||||
|
||||
const openModal = () => mount.querySelector<HTMLElement>('.DocSearch-Button')?.click()
|
||||
|
||||
const load = async (open: boolean) => {
|
||||
openWhenReady = openWhenReady || open
|
||||
if (state === 'ready') {
|
||||
if (open) openModal()
|
||||
return
|
||||
}
|
||||
if (state === 'loading') return
|
||||
state = 'loading'
|
||||
try {
|
||||
const { default: docsearch } = await import('@docsearch/js')
|
||||
docsearch({
|
||||
container: '#docsearch',
|
||||
appId,
|
||||
indexName,
|
||||
apiKey,
|
||||
})
|
||||
state = 'ready'
|
||||
// The bundle renders its (hidden) button and binds its own shortcuts.
|
||||
if (openWhenReady) openModal()
|
||||
} catch {
|
||||
state = 'idle'
|
||||
}
|
||||
}
|
||||
|
||||
input.addEventListener('click', () => {
|
||||
load(true)
|
||||
input.blur()
|
||||
})
|
||||
// Keyboard users: prefetch on focus, open on Enter or when they start typing.
|
||||
input.addEventListener('focus', () => load(false))
|
||||
input.addEventListener('keydown', (event) => {
|
||||
if (event.key === 'Enter' || event.key.length === 1) {
|
||||
event.preventDefault()
|
||||
load(true)
|
||||
input.blur()
|
||||
}
|
||||
})
|
||||
input.addEventListener('pointerenter', () => load(false))
|
||||
document.addEventListener('keydown', (event) => {
|
||||
if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === 'k' && state !== 'ready') {
|
||||
event.preventDefault()
|
||||
load(true)
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@@ -1,6 +1,8 @@
|
||||
---
|
||||
// TOC comes in as a prop from the consuming page (h2/h3 headings from the
|
||||
// markdown content, excluding <!--EXAMPLE-->...<!--/EXAMPLE--> blocks).
|
||||
import Subheader from '@ui/Subheader.astro'
|
||||
import Icon from '@ui/Icon.astro'
|
||||
|
||||
export interface TocItem {
|
||||
/** 2 or 3 (h2/h3); h3 gets the ms-3 indent */
|
||||
@@ -12,9 +14,15 @@ export interface TocItem {
|
||||
|
||||
interface Props {
|
||||
toc?: TocItem[]
|
||||
/** "Edit this page" URL on GitHub; omitted for pages without a source file */
|
||||
editUrl?: string | undefined
|
||||
/** URL of the file implementing the component, from the page's `source` front matter */
|
||||
sourceUrl?: string | undefined
|
||||
/** url of this page's markdown mirror, offered as a copy button */
|
||||
markdownUrl?: string | undefined
|
||||
}
|
||||
|
||||
const { toc = [] } = Astro.props
|
||||
const { toc = [], editUrl, sourceUrl, markdownUrl } = Astro.props
|
||||
|
||||
// shared/data/illustrations.json has 125 entries.
|
||||
const illustrationsCount = 125
|
||||
@@ -23,10 +31,12 @@ const illustrationsCount = 125
|
||||
<!-- BEGIN DOCS TOC -->{
|
||||
toc.length > 0 && (
|
||||
<Fragment>
|
||||
<h3 id="toc-heading">Table of Contents</h3>
|
||||
<nav class="nav nav-vertical" id="toc" aria-labelledby="toc-heading">
|
||||
<Subheader as="h3" id="toc-heading" class="mb-2">
|
||||
On this page
|
||||
</Subheader>
|
||||
<nav class="nav nav-vertical mb-6" id="toc" aria-labelledby="toc-heading">
|
||||
{toc.map((item) => (
|
||||
<a href={`#${item.id}`} class={`nav-link${item.level === 3 ? ' ms-3' : ''}`}>
|
||||
<a href={`#${item.id}`} class={`nav-link${item.level === 3 ? ' docs-toc-sub' : ''}`}>
|
||||
{item.text}
|
||||
</a>
|
||||
))}
|
||||
@@ -42,4 +52,58 @@ const illustrationsCount = 125
|
||||
<h4>{illustrationsCount} sleek illustrations for your startup's visual identity.</h4>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
{
|
||||
(markdownUrl || sourceUrl || editUrl) && (
|
||||
<nav class="docs-page-links mt-6" aria-label="Page tools">
|
||||
{markdownUrl && (
|
||||
<button type="button" class="docs-page-link" data-docs-copy-markdown={markdownUrl}>
|
||||
<Icon name="clipboard" />
|
||||
<span data-docs-copy-label>Copy page as Markdown</span>
|
||||
</button>
|
||||
)}
|
||||
|
||||
{sourceUrl && (
|
||||
<a href={sourceUrl} class="docs-page-link" target="_blank" rel="noopener noreferrer">
|
||||
<Icon name="code" />
|
||||
Source code
|
||||
</a>
|
||||
)}
|
||||
|
||||
{editUrl && (
|
||||
<a href={editUrl} class="docs-page-link" target="_blank" rel="noopener noreferrer">
|
||||
<Icon name="edit" />
|
||||
Edit this page on GitHub
|
||||
</a>
|
||||
)}
|
||||
</nav>
|
||||
)
|
||||
}
|
||||
<!-- END DOCS TOC -->
|
||||
|
||||
<script>
|
||||
// Fetches the .md mirror of the page and puts it on the clipboard, so the
|
||||
// whole page can be pasted into an assistant without hunting for the url.
|
||||
const button = document.querySelector<HTMLButtonElement>('[data-docs-copy-markdown]')
|
||||
|
||||
if (button) {
|
||||
const label = button.querySelector<HTMLElement>('[data-docs-copy-label]')
|
||||
|
||||
button.addEventListener('click', async () => {
|
||||
if (!label) return
|
||||
const url = button.dataset.docsCopyMarkdown
|
||||
if (!url) return
|
||||
try {
|
||||
const response = await fetch(url)
|
||||
await navigator.clipboard.writeText(await response.text())
|
||||
const original = label.textContent
|
||||
label.textContent = 'Copied'
|
||||
setTimeout(() => {
|
||||
label.textContent = original
|
||||
}, 2000)
|
||||
} catch {
|
||||
// clipboard or network refused — leave the label alone
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -9,7 +9,7 @@ import { beautifyHtml, highlightCode, removeHref } from '@shared/lib/code-exampl
|
||||
* - transparent — checkerboard pattern, for components with their own background
|
||||
* - primary — theme-aware white (bg-surface)
|
||||
*/
|
||||
type ExampleBackground = 'surface-secondary' | 'transparent' | 'primary'
|
||||
type ExampleBackground = 'surface-secondary' | 'transparent' | 'primary' | 'dark'
|
||||
|
||||
interface Props {
|
||||
/** raw HTML of the example; when absent — the slot is rendered */
|
||||
@@ -35,6 +35,7 @@ const backgroundClasses: Record<ExampleBackground, string> = {
|
||||
'surface-secondary': 'bg-surface-secondary',
|
||||
'transparent': 'bg-pattern-rectangles',
|
||||
'primary': 'bg-surface',
|
||||
'dark': 'bg-dark',
|
||||
}
|
||||
|
||||
// Strip empty lines from the example HTML.
|
||||
@@ -45,36 +46,43 @@ let html = (htmlProp ?? (await Astro.slots.render('default'))).replace(/^\s*[\r\
|
||||
// code in the panel looks like hand-written HTML.
|
||||
html = html.replace(/<(path|circle|line|polyline|polygon|rect|ellipse)([^>]*?)\s*><\/\1>/g, '<$1$2 />').replace(/'/g, "'")
|
||||
|
||||
const exampleClasses = ['example fs-base border rounded my-5', !raw && 'd-flex flex-wrap justify-content-center', `overflow-${overflow}`, 'position-relative', backgroundClasses[background], className]
|
||||
// Demo and its code panel render as one visually joined group: the demo keeps
|
||||
// only its top corners rounded when a code panel is attached below it.
|
||||
const hasDemo = !codeOnly
|
||||
const hasCode = !hideCode
|
||||
const exampleClasses = ['example fs-base border', hasCode ? 'rounded-top' : 'rounded', !raw && 'd-flex flex-wrap justify-content-center', `overflow-${overflow}`, 'position-relative', backgroundClasses[background], className]
|
||||
|
||||
const innerClasses = ['p-6 w-full', column && 'd-flex gap-3 flex-column', !column && centered && `d-flex flex-fill flex-wrap gap-2 justify-content-center${vertical ? ' align-items-center flex-column' : ' justify-content-center'}`, columnFullWidth && 'd-flex flex-fill flex-column gap-2']
|
||||
|
||||
const highlighted = hideCode ? '' : await highlightCode(beautifyHtml(code ?? html), 'html')
|
||||
---
|
||||
|
||||
<!--EXAMPLE-->{
|
||||
!codeOnly && (
|
||||
<div class:list={exampleClasses} style={height ? `height: ${height}` : undefined}>
|
||||
{raw ? (
|
||||
<Fragment set:html={removeHref(html)} />
|
||||
) : (
|
||||
<div class:list={innerClasses} style={column ? 'max-width: 25rem;' : undefined}>
|
||||
<!--EXAMPLE-->
|
||||
<div class="docs-example my-5">
|
||||
{
|
||||
hasDemo && (
|
||||
<div class:list={exampleClasses} style={height ? `height: ${height}` : undefined}>
|
||||
{raw ? (
|
||||
<Fragment set:html={removeHref(html)} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
) : (
|
||||
<div class:list={innerClasses} style={column ? 'max-width: 25rem;' : undefined}>
|
||||
<Fragment set:html={removeHref(html)} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
{
|
||||
!hideCode && (
|
||||
<div class="position-relative">
|
||||
<a class="btn btn-icon btn-dark position-absolute m-2 top-0 end-0 z-3" data-clipboard-text={code ?? html}>
|
||||
<Icon name="clipboard" />
|
||||
<Icon name="check" class="d-none" />
|
||||
</a>
|
||||
<Fragment set:html={highlighted} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
{
|
||||
hasCode && (
|
||||
<div class:list={['docs-example-code position-relative', hasDemo && 'docs-example-code-attached']}>
|
||||
<button type="button" class="btn btn-icon btn-dark position-absolute m-2 top-0 end-0 z-3" data-clipboard-text={code ?? html} aria-label="Copy code">
|
||||
<Icon name="clipboard" />
|
||||
<Icon name="check" class="d-none" />
|
||||
</button>
|
||||
<Fragment set:html={highlighted} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
<!--/EXAMPLE-->
|
||||
|
||||
@@ -14,7 +14,7 @@ import socials from '@data/socials.json'
|
||||
{
|
||||
socials.map((social) => (
|
||||
<tr>
|
||||
<td>
|
||||
<td class="p-2">
|
||||
<div class={`social social-sm social-app-${social.file}`} />
|
||||
</td>
|
||||
<td>{social.name}</td>
|
||||
|
||||
@@ -9,28 +9,29 @@ interface Props {
|
||||
const { name }: Props = Astro.props
|
||||
---
|
||||
|
||||
<ul class="nav nav-bordered mb-2" role="tablist">
|
||||
{
|
||||
packageManagers.map((manager, i) => {
|
||||
return (
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class={`nav-link${i === 0 ? ' active' : ''}`} id={`${manager.name}-tab`} data-bs-toggle="tab" data-bs-target={`#${manager.name}`} type="button" role="tab" aria-controls={manager.name} aria-selected={i === 0 ? 'true' : 'false'}>
|
||||
<span set:html={manager.icon.replace('<svg ', '<svg class="me-2" ')} />
|
||||
{manager.name}
|
||||
</button>
|
||||
</li>
|
||||
)
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
{
|
||||
packageManagers.map((manager, i) => {
|
||||
return (
|
||||
<div class={`tab-pane${i === 0 ? ' show active' : ''}`} id={`${manager.name}`} role="tabpanel" aria-labelledby={`${manager.name}-tab`}>
|
||||
<Code code={`${manager.command} ${manager.install} ${name}`} lang="bash" />
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
<div>
|
||||
<ul class="nav nav-bordered mb-3" role="tablist">
|
||||
{
|
||||
packageManagers.map((manager, i) => {
|
||||
return (
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class={`nav-link${i === 0 ? ' active' : ''}`} id={`${manager.name}-tab`} data-bs-toggle="tab" data-bs-target={`#${manager.name}`} type="button" role="tab" aria-controls={manager.name} aria-selected={i === 0 ? 'true' : 'false'}>
|
||||
{manager.name}
|
||||
</button>
|
||||
</li>
|
||||
)
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
{
|
||||
packageManagers.map((manager, i) => {
|
||||
return (
|
||||
<div class={`tab-pane${i === 0 ? ' show active' : ''}`} id={`${manager.name}`} role="tabpanel" aria-labelledby={`${manager.name}-tab`}>
|
||||
<Code code={`${manager.command} ${manager.install} ${name}`} lang="bash" />
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,6 +6,13 @@ import { z } from 'astro/zod'
|
||||
// Docs pages live in ./content (not ./pages) so they are not routed by the file
|
||||
// system — pages/[...slug].astro renders them from this collection instead.
|
||||
|
||||
/** One row of the class reference: the class, what it does, and whether it is the default. */
|
||||
const classnameEntry = z.object({
|
||||
class: z.string(),
|
||||
desc: z.string(),
|
||||
default: z.boolean().default(false),
|
||||
})
|
||||
|
||||
/** Accepts both `docs-libs: apexcharts` and `docs-libs: [apexcharts]`. */
|
||||
const stringList = z.union([z.string(), z.array(z.string())]).transform((value) => (Array.isArray(value) ? value : [value]))
|
||||
|
||||
@@ -41,6 +48,14 @@ const docs = defineCollection({
|
||||
'hide-pagination': z.boolean().default(false),
|
||||
/** renders the "Added in X" badge next to the h1 */
|
||||
'added-in': z.string().optional(),
|
||||
/** repo-relative path of the file that implements this component, e.g. "core/scss/ui/_alerts.scss" */
|
||||
'source': z.string().optional(),
|
||||
/**
|
||||
* Class reference for the component, grouped by kind. Rendered above the
|
||||
* page body by DocsClassnames. Colors that come from a palette loop are
|
||||
* listed once as `alert-{color}` rather than one row per generated class.
|
||||
*/
|
||||
'classnames': z.record(z.string(), z.array(classnameEntry)).optional(),
|
||||
})
|
||||
// strict so a mistyped key fails the build instead of being silently dropped
|
||||
.strict()
|
||||
|
||||
@@ -47,8 +47,8 @@ The **Tabler Emails** package is organized into a clear and efficient folder str
|
||||
|
||||
This folder contains 123 email subfolders, each with a specific template. Each email folder contains the following files:
|
||||
|
||||
- Compiled HTML files for light and dark themes. Read more about their usage in the [Compiled templates](/emails/introduction/compiled-html) section.
|
||||
- Source HTML files for light and dark themes. Find more information in the [Source templates](/emails/introduction/source-html) section.
|
||||
- Compiled HTML files for light and dark themes. Read more about their usage in the [Compiled templates](/emails/compiled-html) section.
|
||||
- Source HTML files for light and dark themes. Find more information in the [Source templates](/emails/source-html) section.
|
||||
- Screenshot images for desktop and mobile views.
|
||||
- Assets folder with images used in the email template and the CSS file with styles.
|
||||
|
||||
@@ -7,4 +7,4 @@ summary: Tabler Emails is a set of 80 eye-catching, customizable HTML templates.
|
||||
seoDescription: Tabler Emails is a collection of 80 premium, customizable HTML templates. They are compatible with over 90 email clients and devices.
|
||||
---
|
||||
|
||||
Tabler Emails is a package of ready-to-use HTML email templates. Each template is tested in more than 90 email clients and devices, so your messages look right everywhere. Use the [compiled templates](/emails/introduction/compiled-html) as they are, or customize the [source files](/emails/introduction/source-html) to match your brand.
|
||||
Tabler Emails is a package of ready-to-use HTML email templates. Each template is tested in more than 90 email clients and devices, so your messages look right everywhere. Read about the [package contents](/emails/contents), use the [compiled templates](/emails/compiled-html) as they are, or customize the [source files](/emails/source-html) to match your brand.
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
---
|
||||
title: Introduction
|
||||
seoTitle: Introduction to Tabler Emails
|
||||
description: Learn what the Tabler Emails package includes and how to start using its responsive HTML email templates in your campaigns.
|
||||
summary: Learn what is inside the Tabler Emails package and how to start using the templates in your campaigns.
|
||||
seoDescription: Learn what is inside the Tabler Emails package - folder structure, compiled HTML templates and customizable source files.
|
||||
---
|
||||
|
||||
This section explains what you get in the Tabler Emails package and how to work with it. Read about the [package contents](/emails/introduction/contents), use the [compiled HTML templates](/emails/introduction/compiled-html) right away, or build your own versions from the [source files](/emails/introduction/source-html).
|
||||
@@ -5,6 +5,8 @@ summary: Tabler Icons as a webfont allows you to easily include icons in your pr
|
||||
---
|
||||
|
||||
import TabsPackage from '@components/TabsPackage.astro'
|
||||
import { Code } from 'astro:components'
|
||||
import { site } from '@shared/lib/site.ts'
|
||||
|
||||

|
||||
|
||||
@@ -19,14 +21,12 @@ or just [download from Github](https://github.com/tabler/tabler-icons/releases).
|
||||
|
||||
Link the stylesheet directly from a CDN if you do not want to install the package:
|
||||
|
||||
```html
|
||||
<link
|
||||
<Code lang="html" code={`<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/@tabler/icons-webfont@$ICONS_VERSION/dist/tabler-icons.min.css"
|
||||
/>
|
||||
```
|
||||
href="https://cdn.jsdelivr.net/npm/@tabler/icons-webfont@${site.iconsVersion}/dist/tabler-icons.min.css"
|
||||
/>`} />
|
||||
|
||||
Instead of a specific version, you can use `latest` to always get the newest icons.
|
||||
Swap the version for `latest` to always pull the newest icons, or keep it pinned so the set stays stable.
|
||||
|
||||
## Usage
|
||||
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
---
|
||||
title: EPS version
|
||||
summary: Use the EPS files in print projects and vector editing tools that do not support SVG.
|
||||
description: Download Tabler Icons as EPS files for print projects and vector editing tools that do not support the SVG format.
|
||||
---
|
||||
|
||||
import TabsPackage from '@components/TabsPackage.astro'
|
||||
|
||||

|
||||
|
||||
## Installation
|
||||
|
||||
<TabsPackage name="@tabler/icons-eps" />
|
||||
|
||||
or just [download from Github](https://github.com/tabler/tabler-icons/releases).
|
||||
|
||||
All EPS files are stored in `icons` subdirectory.
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Static files
|
||||
description: Download Tabler Icons as static files in SVG, PNG, EPS, and PDF formats. Pick the format that fits your design or development workflow.
|
||||
summary: Static files provide multiple formats of Tabler Icons, including EPS, PDF, PNG, and SVG, offering flexibility for different design and development workflows.
|
||||
description: Download Tabler Icons as static files in SVG, PNG and PDF formats. Pick the format that fits your design or development workflow.
|
||||
summary: Static files provide multiple formats of Tabler Icons, including PDF, PNG and SVG, offering flexibility for different design and development workflows.
|
||||
---
|
||||
|
||||
Every Tabler icon is available as a set of static files. Download [SVG](/icons/static-files/svg) for the web, [PNG](/icons/static-files/png) for quick mockups, or [EPS](/icons/static-files/eps) and [PDF](/icons/static-files/pdf) for print and vector editing tools. Pick the format that fits your workflow.
|
||||
Every Tabler icon is available as a set of static files. Download [SVG](/icons/static-files/svg) for the web, [PNG](/icons/static-files/png) for quick mockups, or [PDF](/icons/static-files/pdf) for print and vector editing tools. Pick the format that fits your workflow.
|
||||
|
||||
@@ -5,6 +5,8 @@ description: Download Tabler Icons as PDF files, ready to place in documents, pr
|
||||
---
|
||||
|
||||
import TabsPackage from '@components/TabsPackage.astro'
|
||||
import { Code } from 'astro:components'
|
||||
import { site } from '@shared/lib/site.ts'
|
||||
|
||||

|
||||
|
||||
@@ -15,4 +17,27 @@ import TabsPackage from '@components/TabsPackage.astro'
|
||||
|
||||
or just [download from Github](https://github.com/tabler/tabler-icons/releases).
|
||||
|
||||
All PDF files are stored in `icons` subdirectory.
|
||||
Files live in `icons/outline` and `icons/filled`, one PDF per icon, named after the icon.
|
||||
|
||||
## Usage
|
||||
|
||||
A PDF icon is a vector file, so it stays sharp at any size and prints cleanly. Place it the same way as any other vector asset.
|
||||
|
||||
- **Documents and presentations.** Insert the file directly in Word, Pages, Google Docs, Keynote or PowerPoint. Scaling it up will not blur it.
|
||||
- **Print and layout tools.** InDesign, Affinity Publisher and Scribus place PDF files natively, keeping the paths editable.
|
||||
- **Vector editors.** Illustrator, Affinity Designer and Inkscape open a PDF icon as editable paths, so you can change the stroke or recolour it.
|
||||
|
||||
Each icon is drawn as a stroke, not a filled shape. Recolour the stroke rather than the fill, and keep the stroke width proportional when you resize - otherwise a large icon looks thin and a small one looks heavy.
|
||||
|
||||
## CDN
|
||||
|
||||
Load a single icon straight from the package without installing it:
|
||||
|
||||
<Code lang="html" code={`https://unpkg.com/@tabler/icons-pdf@${site.iconsVersion}/icons/outline/home.pdf
|
||||
https://unpkg.com/@tabler/icons-pdf@${site.iconsVersion}/icons/filled/home.pdf`} />
|
||||
|
||||
Swap the version for `latest` to always pull the newest icons, or keep it pinned so the set stays stable.
|
||||
|
||||
## When to use another format
|
||||
|
||||
Use [SVG](/icons/static-files/svg) on the web - it is smaller and can be styled with CSS. Use [PNG](/icons/static-files/png) where vectors are not supported at all. PDF is for documents and print.
|
||||
|
||||
@@ -5,6 +5,8 @@ description: Download Tabler Icons as PNG files - raster images for mockups, cha
|
||||
---
|
||||
|
||||
import TabsPackage from '@components/TabsPackage.astro'
|
||||
import { Code } from 'astro:components'
|
||||
import { site } from '@shared/lib/site.ts'
|
||||
|
||||

|
||||
|
||||
@@ -23,16 +25,12 @@ All PNG files are stored in `icons` subdirectory.
|
||||
|
||||
Load the outline version of an icon as an image straight from the `icons/outline` directory of the CDN package:
|
||||
|
||||
```html
|
||||
<img src="https://unpkg.com/@tabler/icons-png@$ICONS_VERSION/icons/outline/home.png" />
|
||||
```
|
||||
<Code lang="html" code={`<img src="https://unpkg.com/@tabler/icons-png@${site.iconsVersion}/icons/outline/home.png" />`} />
|
||||
|
||||
### Filled version
|
||||
|
||||
Use the `icons/filled` path to load the filled version of an icon:
|
||||
|
||||
```html
|
||||
<img src="https://unpkg.com/@tabler/icons-png@$ICONS_VERSION/icons/filled/home.png" />
|
||||
```
|
||||
<Code lang="html" code={`<img src="https://unpkg.com/@tabler/icons-png@${site.iconsVersion}/icons/filled/home.png" />`} />
|
||||
|
||||
Instead of a specific version, you can use `latest` to always get the newest icons.
|
||||
Swap the version for `latest` to always pull the newest icons, or keep it pinned so the set stays stable.
|
||||
|
||||
@@ -5,6 +5,8 @@ description: Download Tabler Icons as SVG files that scale without quality loss.
|
||||
---
|
||||
|
||||
import TabsPackage from '@components/TabsPackage.astro'
|
||||
import { Code } from 'astro:components'
|
||||
import { site } from '@shared/lib/site.ts'
|
||||
import Icon from '@ui/Icon.astro'
|
||||
import Example from '@components/Example.astro'
|
||||
|
||||
@@ -33,10 +35,9 @@ If you load an icon as an image, you can modify its size using CSS.
|
||||
You can paste the content of the icon file into your HTML code to display it on the page.
|
||||
|
||||
<Example codeOnly>
|
||||
<a href="">
|
||||
<Icon name="disabled" />
|
||||
Click me
|
||||
</a>
|
||||
<a href="">
|
||||
<Icon name="disabled" /> Click me
|
||||
</a>
|
||||
</Example>
|
||||
|
||||
Thanks to that, you can change the size, color and the `stroke-width` of the icons with CSS code.
|
||||
@@ -66,16 +67,12 @@ Add an icon to be displayed on your page with the following markup (`activity` i
|
||||
|
||||
Load the outline version of an icon as an image straight from the `icons/outline` directory of the CDN package:
|
||||
|
||||
```html
|
||||
<img src="https://unpkg.com/@tabler/icons@$ICONS_VERSION/icons/outline/home.svg" />
|
||||
```
|
||||
<Code lang="html" code={`<img src="https://unpkg.com/@tabler/icons@${site.iconsVersion}/icons/outline/home.svg" />`} />
|
||||
|
||||
### Filled version
|
||||
|
||||
Use the `icons/filled` path to load the filled version of an icon:
|
||||
|
||||
```html
|
||||
<img src="https://unpkg.com/@tabler/icons@$ICONS_VERSION/icons/filled/home.svg" />
|
||||
```
|
||||
<Code lang="html" code={`<img src="https://unpkg.com/@tabler/icons@${site.iconsVersion}/icons/filled/home.svg" />`} />
|
||||
|
||||
Instead of a specific version, you can use `latest` to always get the newest icons.
|
||||
Swap the version for `latest` to always pull the newest icons, or keep it pinned so the set stays stable.
|
||||
|
||||
+1
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: Contents
|
||||
order: 2
|
||||
description: Explore the folder structure of the Tabler Illustrations package and learn where to find each format, color variant, and theme.
|
||||
summary: The Tabler Illustrations package is thoughtfully structured to provide designers and developers with an array of high-quality assets. This guide explores the various folders and their contents, helping users make the most of these resources.
|
||||
---
|
||||
File diff suppressed because one or more lines are too long
@@ -7,3 +7,5 @@ summary: Tabler Illustrations is a collection of customizable SVG illustrations
|
||||
|
||||
<img src="/img/cover-illustrations.png" alt="Tabler Illustrations" class="hide-theme-dark" width="1600" height="750" />
|
||||
<img src="/img/cover-illustrations-dark.png" alt="Tabler Illustrations" class="hide-theme-light" width="1600" height="750" />
|
||||
|
||||
This section covers everything you need to start with Tabler Illustrations. [Preview the collection](/illustrations/preview), check [what is inside the package](/illustrations/contents), learn how to [customize the illustrations](/illustrations/customization), and read the [license terms](/illustrations/license).
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,7 +0,0 @@
|
||||
---
|
||||
title: Introduction
|
||||
description: Introduction to Tabler Illustrations and their key features.
|
||||
summary: Tabler Illustrations is a collection of high-quality, customizable illustrations designed to enhance the visual appeal of your projects. These illustrations align seamlessly with the Tabler design system, making it easy to create engaging and cohesive designs for websites, apps, and presentations
|
||||
---
|
||||
|
||||
This section covers everything you need to start with Tabler Illustrations. [Preview the collection](/illustrations/introduction/preview), check [what is inside the package](/illustrations/introduction/contents), learn how to [customize the illustrations](/illustrations/introduction/customization), and read the [license terms](/illustrations/introduction/license).
|
||||
@@ -1,22 +0,0 @@
|
||||
---
|
||||
title: Preview
|
||||
summary: 'Tabler Illustrations offers 80 illustrations in two themes: light and dark. You can use them in your projects to enhance the visual appeal and convey messages effectively.'
|
||||
description: Browse all Tabler Illustrations in light and dark themes.
|
||||
---
|
||||
|
||||
import illustrations from '@data/illustrations.json'
|
||||
export const allIllustrations = illustrations.sort()
|
||||
|
||||
Look at full list of illustrations below and see how they look. Find out more and purchase Tabler Illustrations at [our website](https://tabler.io/illustrations).
|
||||
|
||||
<div class="row g-2 gy-6">
|
||||
{allIllustrations.map((illustration, i) => {
|
||||
return (
|
||||
<div class="col-6 col-md-4 col-lg-3 text-center">
|
||||
<img src={`/static/illustrations/light/${illustration}.png`} alt={illustration} class="hide-theme-dark" />
|
||||
<img src={`/static/illustrations/dark/${illustration}.png`} alt={illustration} class="hide-theme-light" />
|
||||
<code>{illustration}</code>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
+1
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: License
|
||||
order: 4
|
||||
summary: Read what you can and cannot do with Tabler Illustrations under the personal and team licenses.
|
||||
description: License terms for personal and team use of Tabler Illustrations.
|
||||
---
|
||||
@@ -0,0 +1,48 @@
|
||||
---
|
||||
title: Preview
|
||||
order: 1
|
||||
summary: 'Tabler Illustrations offers 80 illustrations in two themes: light and dark. You can use them in your projects to enhance the visual appeal and convey messages effectively.'
|
||||
description: Browse all Tabler Illustrations in light and dark themes.
|
||||
---
|
||||
|
||||
import illustrations from '@data/illustrations.json'
|
||||
export const allIllustrations = illustrations.sort()
|
||||
|
||||
Every illustration comes in a light and a dark variant, drawn to sit on the matching page background. The name under each one is the file name, the same in every format the package ships - see the [folder structure](/illustrations/contents) for where each format lives.
|
||||
|
||||
## Using an illustration
|
||||
|
||||
The simplest way is an `img` element pointing at the SVG file:
|
||||
|
||||
```html
|
||||
<img src="/illustrations/light/undraw-empty.svg" alt="" class="w-100" />
|
||||
```
|
||||
|
||||
Leave `alt` empty when the illustration only decorates a block that already has a heading and text, which is the usual case in an [empty state](/ui/components/empty). Write real `alt` text only when the picture carries information nothing else on the page does.
|
||||
|
||||
## Following the color mode
|
||||
|
||||
To switch variants with the page, place both files and let Tabler hide the one that does not apply. That is what this page does:
|
||||
|
||||
```html
|
||||
<img src="/illustrations/light/undraw-empty.svg" alt="" class="hide-theme-dark" />
|
||||
<img src="/illustrations/dark/undraw-empty.svg" alt="" class="hide-theme-light" />
|
||||
```
|
||||
|
||||
The `svg-css-autodark` folder holds a single-file version that follows the color mode on its own, with no second image. See [customization](/illustrations/customization#autodark-mode) for how it works and how to recolor it.
|
||||
|
||||
## All illustrations
|
||||
|
||||
Find out more and purchase Tabler Illustrations at [our website](https://tabler.io/illustrations).
|
||||
|
||||
<div class="row g-2 gy-6">
|
||||
{allIllustrations.map((illustration, i) => {
|
||||
return (
|
||||
<div class="col-6 col-md-4 col-lg-3 text-center">
|
||||
<img src={`/static/illustrations/light/${illustration}.png`} alt={illustration} class="hide-theme-dark" />
|
||||
<img src={`/static/illustrations/dark/${illustration}.png`} alt={illustration} class="hide-theme-light" />
|
||||
<code>{illustration}</code>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
@@ -32,3 +32,11 @@ The gray palette is a great choice for creating a neutral background for your de
|
||||
Use the colors of popular social networks to create a recognizable design and make it easier for users to interact with your product.
|
||||
|
||||
<Colors colors={site.socialColors} />
|
||||
|
||||
## Accessibility
|
||||
|
||||
- A colour name is not a meaning. `text-red` looks like an error to most users, but a screen reader announces nothing, so keep the meaning in the text.
|
||||
- Body text needs a contrast ratio of at least 4.5:1, and large text at least 3:1. The lighter `-lt` variants are backgrounds for dark text, not text colours.
|
||||
- Check both colour modes. A pair that passes in light can fail in dark, and Tabler switches many tokens with `light-dark()`.
|
||||
- The social colours are brand colours. They are picked to be recognisable, not readable - do not use them for text on a white background without checking.
|
||||
- Never separate two states by hue alone. Add a label, an icon, or a shape.
|
||||
|
||||
@@ -9,7 +9,7 @@ import Prose from '@ui/Prose.astro';
|
||||
|
||||
## How it works
|
||||
|
||||
Wrap your content in the `.prose` class to apply long-form typography styles to headings, paragraphs, lists, tables, and other common elements. This is especially useful when rendering Markdown, MDX, or content from a [WYSIWYG editor](/ui/components/wysiwyg).
|
||||
Wrap your content in the `.prose` class to apply long-form typography styles to headings, paragraphs, lists, tables, and other common elements. This is especially useful when rendering Markdown, MDX, or content from a [WYSIWYG editor](/ui/plugins/wysiwyg).
|
||||
|
||||
- Sets a base `font-size` and `line-height` for comfortable reading.
|
||||
- Normalizes list spacing and nested list indentation.
|
||||
@@ -21,7 +21,14 @@ Wrap your content in the `.prose` class to apply long-form typography styles to
|
||||
This example shows typical content wrapped in `.prose`.
|
||||
|
||||
<Example>
|
||||
<Prose> <h1>Getting started with documentation</h1> <p> Writing clear and effective documentation is essential for any project. When you create content that others will read and use, proper formatting makes all the difference. <em>Good documentation</em> helps users understand complex concepts quickly and efficiently. </p> <blockquote> <p>Documentation is a love letter that you write to your future self.</p> </blockquote> <p> The foundation of great documentation starts with <strong>understanding your audience</strong> and their needs. </p> </Prose>
|
||||
<Prose>
|
||||
<h1>Getting started with documentation</h1>
|
||||
<p> Writing clear and effective documentation is essential for any project. When you create content that others will read and use, proper formatting makes all the difference. <em>Good documentation</em> helps users understand complex concepts quickly and efficiently. </p>
|
||||
<blockquote>
|
||||
<p>Documentation is a love letter that you write to your future self.</p>
|
||||
</blockquote>
|
||||
<p> The foundation of great documentation starts with <strong>understanding your audience</strong> and their needs. </p>
|
||||
</Prose>
|
||||
</Example>
|
||||
|
||||
## Callout
|
||||
@@ -29,7 +36,11 @@ This example shows typical content wrapped in `.prose`.
|
||||
Wrap a short note in `.callout` to make it stand out from the surrounding text, for example a tip or a warning. It works inside or outside `.prose`.
|
||||
|
||||
<Example>
|
||||
<div class="callout"> <p><strong>Tip.</strong> Keep a glossary of terms your readers might not know. It saves you from re-explaining the same concept in every article.</p> </div>
|
||||
<div class="callout">
|
||||
<p>
|
||||
<strong>Tip.</strong> Keep a glossary of terms your readers might not know. It saves you from re-explaining the same concept in every article.
|
||||
</p>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Inline HTML elements
|
||||
@@ -55,7 +66,10 @@ Headings help readers scan long documents quickly. Use them to create a clear hi
|
||||
Inline code is available with `<code>`. For multi-line snippets, use `<pre><code>`.
|
||||
|
||||
<Example>
|
||||
<Prose> <p>Inline code looks like <code>console.log("Hello")</code> and uses monospace styling.</p> <pre><code>// Create a function that returns a sum function add(a, b) { return a + b; } </code></pre> </Prose>
|
||||
<Prose>
|
||||
<p> Inline code looks like <code>console.log("Hello")</code> and uses monospace styling. </p>
|
||||
<pre><code>// Create a function that returns a sum function add(a, b) { return a + b; } </code></pre>
|
||||
</Prose>
|
||||
</Example>
|
||||
|
||||
### Lists
|
||||
@@ -63,7 +77,18 @@ Inline code is available with `<code>`. For multi-line snippets, use `<pre><code
|
||||
Use ordered lists for steps and unordered lists for related points.
|
||||
|
||||
<Example>
|
||||
<Prose> <ol> <li>Start with the most important information.</li> <li>Provide context before technical details.</li> <li>Include practical examples.</li> </ol> <ul> <li>Write clear, concise list items.</li> <li>Keep the structure consistent.</li> <li>Avoid overly long items.</li> </ul> </Prose>
|
||||
<Prose>
|
||||
<ol>
|
||||
<li>Start with the most important information.</li>
|
||||
<li>Provide context before technical details.</li>
|
||||
<li>Include practical examples.</li>
|
||||
</ol>
|
||||
<ul>
|
||||
<li>Write clear, concise list items.</li>
|
||||
<li>Keep the structure consistent.</li>
|
||||
<li>Avoid overly long items.</li>
|
||||
</ul>
|
||||
</Prose>
|
||||
</Example>
|
||||
|
||||
### Images
|
||||
@@ -71,7 +96,11 @@ Use ordered lists for steps and unordered lists for related points.
|
||||
Images should support the text and provide useful context.
|
||||
|
||||
<Example>
|
||||
<Prose> <img src="/static/photos/cup-of-coffee-and-an-open-book.jpg" alt="Open book and coffee" /> <img src="/static/photos/book-on-the-grass.jpg" alt="Book on the grass" /> <img src="/static/photos/stylish-workspace-with-macbook-pro.jpg" alt="Workspace with laptop" /> </Prose>
|
||||
<Prose>
|
||||
<img src="/static/photos/cup-of-coffee-and-an-open-book.jpg" alt="Open book and coffee" />
|
||||
<img src="/static/photos/book-on-the-grass.jpg" alt="Book on the grass" />
|
||||
<img src="/static/photos/stylish-workspace-with-macbook-pro.jpg" alt="Workspace with laptop" />
|
||||
</Prose>
|
||||
</Example>
|
||||
|
||||
### Tables
|
||||
@@ -79,5 +108,45 @@ Images should support the text and provide useful context.
|
||||
Tables work best for comparing related data points.
|
||||
|
||||
<Example>
|
||||
<Prose> <table> <thead> <tr> <th>Name</th> <th>Up-votes</th> <th>Down-votes</th> </tr> </thead> <tbody> <tr> <td>Alice</td> <td>10</td> <td>11</td> </tr> <tr> <td>Bob</td> <td>4</td> <td>3</td> </tr> <tr> <td>Charlie</td> <td>7</td> <td>9</td> </tr> <tr> <td>Totals</td> <td>21</td> <td>23</td> </tr> </tbody> </table> </Prose>
|
||||
<Prose>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Up-votes</th>
|
||||
<th>Down-votes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Alice</td>
|
||||
<td>10</td>
|
||||
<td>11</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Bob</td>
|
||||
<td>4</td>
|
||||
<td>3</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Charlie</td>
|
||||
<td>7</td>
|
||||
<td>9</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Totals</td>
|
||||
<td>21</td>
|
||||
<td>23</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</Prose>
|
||||
</Example>
|
||||
|
||||
## Accessibility
|
||||
|
||||
- `prose` styles content you do not control, so the headings inside it have to keep a sensible order - do not jump from `h2` to `h4`.
|
||||
- Images in prose need `alt` text. Use `alt=""` only when the caption already says the same thing.
|
||||
- Links should make sense on their own. "Read more" repeated ten times gives a screen reader user a list of identical entries.
|
||||
- Tables in prose need a `th` row. Prose styles them, but only the markup makes them readable.
|
||||
- Do not rely on the prose colours for meaning. Keep the emphasis in `strong` and `em`.
|
||||
|
||||
@@ -5,7 +5,6 @@ description: Learn how Tabler styles headings, paragraphs, and text elements to
|
||||
related: [/ui/base/prose]
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
import Prose from '@ui/Prose.astro';
|
||||
|
||||
## Headings
|
||||
|
||||
@@ -15,7 +14,12 @@ The `h1` tag is the highest level and the `h6` tag is the lowest level.
|
||||
Below are examples of headings with different levels:
|
||||
|
||||
<Example>
|
||||
<h1>H1 Heading</h1> <h2>H2 Heading</h2> <h3>H3 Heading</h3> <h4>H4 Heading</h4> <h5>H5 Heading</h5> <h6>H6 Heading</h6>
|
||||
<h1>H1 Heading</h1>
|
||||
<h2>H2 Heading</h2>
|
||||
<h3>H3 Heading</h3>
|
||||
<h4>H4 Heading</h4>
|
||||
<h5>H5 Heading</h5>
|
||||
<h6>H6 Heading</h6>
|
||||
</Example>
|
||||
|
||||
## Paragraphs
|
||||
@@ -29,10 +33,27 @@ Organize longer pieces of text into paragraphs using the `p` tag. It is the most
|
||||
If you use a second paragraph, it will be separated from the first one by a blank line.
|
||||
|
||||
<Example vertical>
|
||||
<p> Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. </p> <p>At vero eos et accusam et justo duo dolores et ea rebum.</p>
|
||||
<p> Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. </p>
|
||||
<p>At vero eos et accusam et justo duo dolores et ea rebum.</p>
|
||||
</Example>
|
||||
|
||||
|
||||
Add the `lead` class to the opening paragraph of a section. In Tabler it does not enlarge the text the way Bootstrap does - it prints the paragraph in the secondary color, so the intro reads as a subtitle under the heading.
|
||||
|
||||
<Example vertical>
|
||||
<h2>Installation</h2>
|
||||
<p class="lead">Everything you need to get Tabler running in your project.</p>
|
||||
<p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore.</p>
|
||||
</Example>
|
||||
|
||||
## Selected text
|
||||
|
||||
`text-selected` paints a run of text with the same highlight the browser uses for a selection. Use it to point at a fragment in a tutorial or a changelog, where a real selection cannot be shown.
|
||||
|
||||
<Example>
|
||||
<p>To select text using your mouse, click and drag the cursor over the text <span class="text-selected">you want to highlight</span>.</p>
|
||||
</Example>
|
||||
|
||||
## Semantic text elements
|
||||
|
||||
Use a variety of semantic text elements, depending on how you want to display particular fragments of content.
|
||||
@@ -40,7 +61,26 @@ Use a variety of semantic text elements, depending on how you want to display pa
|
||||
Here are examples of semantic text elements:
|
||||
|
||||
<Example>
|
||||
<div> <abbr title="Internationalization">I18N</abbr> </div> <div> <strong>Bold</strong> </div> <div> <cite>Citation</cite> </div> <div> <code>Hello World!</code> </div> <div> <del>Deleted</del> </div> <div> <em>Emphasis</em> </div> <div> <i>Italic</i> </div> <div> <ins>Inserted</ins> </div> <div> <kbd>Ctrl + S</kbd> </div> <div> <mark>Highlighted</mark> </div> <div> <s>Strikethrough</s> </div> <div> <samp>Sample</samp> </div> <div> Text <sub>Subscript</sub> </div> <div> Text <sup>Superscript</sup> </div> <div> <time>20:00</time> </div> <div> <u>Underline</u> </div> <div> <var>x</var> = <var>y</var> + 2 </div>
|
||||
<div><abbr title="Internationalization">I18N</abbr></div>
|
||||
<div><strong>Bold</strong></div>
|
||||
<div><cite>Citation</cite></div>
|
||||
<div><code>Hello World!</code></div>
|
||||
<div><del>Deleted</del></div>
|
||||
<div><em>Emphasis</em></div>
|
||||
<div><i>Italic</i></div>
|
||||
<div><ins>Inserted</ins></div>
|
||||
<div><kbd>Ctrl + S</kbd></div>
|
||||
<div><mark>Highlighted</mark></div>
|
||||
<div><s>Strikethrough</s></div>
|
||||
<div><samp>Sample</samp></div>
|
||||
<div> Text <sub>Subscript</sub> </div>
|
||||
<div> Text <sup>Superscript</sup> </div>
|
||||
<div><time>20:00</time></div>
|
||||
<div><u>Underline</u></div>
|
||||
<div>
|
||||
<var>x</var> =
|
||||
<var>y</var> + 2
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Horizontal rules
|
||||
@@ -48,7 +88,11 @@ Here are examples of semantic text elements:
|
||||
Use the `hr` tag to represent a thematic break between paragraphs within one section.
|
||||
|
||||
<Example>
|
||||
<div> <p> Lorem ipsum dolor sit amet, consectetur adipisicing elit. A atque ex excepturi fuga magnam nam reiciendis velit. Amet eius eos eveniet fuga in ipsa, ipsum voluptatum. Dolorem expedita quibusdam veniam? </p> <hr /> <p> Lorem ipsum dolor sit amet, consectetur adipisicing elit. A atque ex excepturi fuga magnam nam reiciendis velit. Amet eius eos eveniet fuga in ipsa, ipsum voluptatum. Dolorem expedita quibusdam veniam? </p> </div>
|
||||
<div>
|
||||
<p> Lorem ipsum dolor sit amet, consectetur adipisicing elit. A atque ex excepturi fuga magnam nam reiciendis velit. Amet eius eos eveniet fuga in ipsa, ipsum voluptatum. Dolorem expedita quibusdam veniam? </p>
|
||||
<hr />
|
||||
<p> Lorem ipsum dolor sit amet, consectetur adipisicing elit. A atque ex excepturi fuga magnam nam reiciendis velit. Amet eius eos eveniet fuga in ipsa, ipsum voluptatum. Dolorem expedita quibusdam veniam? </p>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Horizontal rules with label
|
||||
@@ -56,7 +100,15 @@ Use the `hr` tag to represent a thematic break between paragraphs within one sec
|
||||
You can also add a label to a horizontal rule and align it as you see fit. Centered label is the default.
|
||||
|
||||
<Example>
|
||||
<p> Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. </p> <div class="hr-text"> <span>Rule text</span> </div> <p> At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. </p> <div class="hr-text hr-text-center"> <span>Rule text</span> </div> <p> Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. </p> <div class="hr-text hr-text-start"> <span>Rule text</span> </div> <p> At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. </p> <div class="hr-text hr-text-end"> <span>Rule text</span> </div> <p> Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. </p>
|
||||
<p> Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. </p>
|
||||
<div class="hr-text"><span>Rule text</span></div>
|
||||
<p> At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. </p>
|
||||
<div class="hr-text"><span>Rule text</span></div>
|
||||
<p> Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. </p>
|
||||
<div class="hr-text hr-text-start"><span>Rule text</span></div>
|
||||
<p> At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. </p>
|
||||
<div class="hr-text hr-text-end"><span>Rule text</span></div>
|
||||
<p> Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. </p>
|
||||
</Example>
|
||||
|
||||
## Optimized for different alphabets
|
||||
@@ -64,7 +116,15 @@ You can also add a label to a horizontal rule and align it as you see fit. Cente
|
||||
Tabler has been optimized to correctly display content in any language. It supports most Asian, African and Middle Eastern languages.
|
||||
|
||||
<Example>
|
||||
<p>汉字</p> <p>日本語の表記体系</p> <p>Кириллица</p> <p>Eλληνική</p> <p>ქართული დამწერლობა</p> <p>Հայերենի այբուբեն</p> <p>الحروف العربية</p> <p>אלפבית עברי</p> <p>อักษรไทย</p>
|
||||
<p>汉字</p>
|
||||
<p>日本語の表記体系</p>
|
||||
<p>Кириллица</p>
|
||||
<p>Eλληνική</p>
|
||||
<p>ქართული დამწერლობა</p>
|
||||
<p>Հայերենի այբուբեն</p>
|
||||
<p>الحروف العربية</p>
|
||||
<p>אלפבית עברי</p>
|
||||
<p>อักษรไทย</p>
|
||||
</Example>
|
||||
|
||||
## Text transform
|
||||
@@ -72,7 +132,9 @@ Tabler has been optimized to correctly display content in any language. It suppo
|
||||
Transform the content of components with text capitalization classes.
|
||||
|
||||
<Example>
|
||||
<p class="text-lowercase">Lowercased text.</p> <p class="text-uppercase">Uppercased text.</p> <p class="text-capitalize">Capitalized text.</p>
|
||||
<p class="text-lowercase">Lowercased text.</p>
|
||||
<p class="text-uppercase">Uppercased text.</p>
|
||||
<p class="text-capitalize">Capitalized text.</p>
|
||||
</Example>
|
||||
|
||||
## Letter spacing
|
||||
@@ -80,7 +142,9 @@ Transform the content of components with text capitalization classes.
|
||||
Control the tracking (letter spacing) of an element and make it tight, wide or normal.
|
||||
|
||||
<Example>
|
||||
<p class="tracking-tight">Lorem ipsum dolor sit amet. Tight letter spacing.</p> <p class="tracking-normal">Lorem ipsum dolor sit amet. Normal letter spacing.</p> <p class="tracking-wide">Lorem ipsum dolor sit amet. Wide letter spacing.</p>
|
||||
<p class="tracking-tight">Lorem ipsum dolor sit amet. Tight letter spacing.</p>
|
||||
<p class="tracking-normal">Lorem ipsum dolor sit amet. Normal letter spacing.</p>
|
||||
<p class="tracking-wide">Lorem ipsum dolor sit amet. Wide letter spacing.</p>
|
||||
</Example>
|
||||
|
||||
## Line height
|
||||
@@ -88,7 +152,10 @@ Control the tracking (letter spacing) of an element and make it tight, wide or n
|
||||
Control the leading (line height) of an element using the `.lh-*` classes. The line height is the vertical space between lines of text.
|
||||
|
||||
<Example>
|
||||
<p class="lh-1"> This is the long text with line height 1. Lorem ipsum dolor sit amet. Dolor sit amet. </p> <p class="lh-sm"> This is the long text with small line height. Lorem ipsum dolor sit amet. Dolor sit amet. </p> <p class="lh-base"> This is the long text with base line height. Lorem ipsum dolor sit amet. Dolor sit amet. </p> <p class="lh-lg"> This is the long text with large line height. Lorem ipsum dolor sit amet. Dolor sit amet. </p>
|
||||
<p class="lh-1"> This is the long text with line height 1.<br />Lorem ipsum dolor sit amet.<br />Dolor sit amet. </p>
|
||||
<p class="lh-sm"> This is the long text with small line height.<br />Lorem ipsum dolor sit amet.<br />Dolor sit amet. </p>
|
||||
<p class="lh-base"> This is the long text with base line height.<br />Lorem ipsum dolor sit amet.<br />Dolor sit amet. </p>
|
||||
<p class="lh-lg"> This is the long text with large line height.<br />Lorem ipsum dolor sit amet.<br />Dolor sit amet. </p>
|
||||
</Example>
|
||||
|
||||
## Antialiasing
|
||||
@@ -98,7 +165,8 @@ Control the font smoothing of an element.
|
||||
Use the `.antialiased` utility to render text using subpixel antialiasing or use the `.subpixel-antialiased` utility to remove antialiasing.
|
||||
|
||||
<Example>
|
||||
<div class="antialiased">Text with antialiasing</div> <div class="subpixel-antialiased">Text without antialiasing</div>
|
||||
<div class="antialiased">Text with antialiasing</div>
|
||||
<div class="subpixel-antialiased">Text without antialiasing</div>
|
||||
</Example>
|
||||
|
||||
## Keyboard input
|
||||
@@ -106,13 +174,23 @@ Use the `.antialiased` utility to render text using subpixel antialiasing or use
|
||||
Use the `<kbd>` to indicate input that is typically entered via keyboard.
|
||||
|
||||
<Example>
|
||||
To edit settings, press <kbd>ctrl</kbd> + <kbd>,</kbd> or <kbd>ctrl</kbd> + <kbd>C</kbd>.
|
||||
To edit settings, press
|
||||
<kbd>ctrl</kbd> +
|
||||
<kbd>,</kbd> or
|
||||
<kbd>ctrl</kbd> +
|
||||
<kbd>C</kbd> .
|
||||
</Example>
|
||||
|
||||
## Prose
|
||||
|
||||
If you can't use the CSS classes you want, or you just want to use HTML tags, use the `.prose` class in a container. It will apply the default styles for markdown elements. The `.markdown` class is an alias and will be removed in a future release. The `.wysiwyg` integration is deprecated and will be removed in a future release. See the [Prose page](/ui/base/prose) for full examples.
|
||||
If you can't use the CSS classes you want, or you just want to use HTML tags, wrap the content in the `.prose` class and it picks up the default styles for markdown elements. See the [Prose page](/ui/base/prose) for the full set of examples.
|
||||
|
||||
<Example>
|
||||
<Prose> <h1>Hello World</h1> <p> Lorem ipsum<sup>[1]</sup> dolor sit amet, consectetur adipiscing elit. Nulla accumsan, metus ultrices eleifend gravida, nulla nunc varius lectus, nec rutrum justo nibh eu lectus. Ut vulputate semper dui. Fusce erat odio, sollicitudin vel erat vel, interdum mattis neque. Sub<sub >script</sub > works as well! </p> <h2>Second level</h2> <p> Curabitur accumsan turpis pharetra <strong>augue tincidunt</strong> blandit. Quisque condimentum maximus mi, sit amet commodo arcu rutrum id. Proin pretium urna vel cursus venenatis. Suspendisse potenti. Etiam mattis sem rhoncus lacus dapibus facilisis. Donec at dignissim dui. Ut et neque nisl. </p> <ul> <li>In fermentum leo eu lectus mollis, quis dictum mi aliquet.</li> <li>Morbi eu nulla lobortis, lobortis est in, fringilla felis.</li> <li>Aliquam nec felis in sapien venenatis viverra fermentum nec lectus.</li> <li>Ut non enim metus.</li> </ul> </Prose>
|
||||
</Example>
|
||||
## Accessibility
|
||||
|
||||
- Headings carry the structure of the page. Use `h1` to `h6` in order, and the `.h1` to `.h6` classes when you need the look of a heading on something that is not one.
|
||||
- One `h1` per page, naming that page.
|
||||
- Do not use a heading to make text big, and do not use `strong` in place of a heading. A screen reader user navigates by heading, so a fake one is a missing landmark.
|
||||
- Body text should not go below 0.875rem, and it has to stay readable at 200% zoom without horizontal scrolling.
|
||||
- Keep line length around 60 to 80 characters. Longer lines are hard to track, especially with dyslexia or low vision.
|
||||
- `text-uppercase` changes the look, not the text, but some screen readers read an already-uppercase word letter by letter. Write the word normally and let CSS transform it.
|
||||
- Do not use `letter-spacing` or `line-height` utilities to squeeze text below the browser default. Users need that space.
|
||||
|
||||
@@ -3,6 +3,32 @@ title: Accordion
|
||||
summary: Use accordion panels to group related content and show one section at a time.
|
||||
description: Build collapsible content sections with accordion classes and modifiers.
|
||||
related: [/ui/components/tab]
|
||||
source: core/scss/ui/_accordion.scss
|
||||
classnames:
|
||||
component:
|
||||
- class: accordion
|
||||
desc: Container element
|
||||
part:
|
||||
- class: accordion-item
|
||||
desc: One collapsible section
|
||||
- class: accordion-header
|
||||
desc: Heading that holds the toggle button
|
||||
- class: accordion-button
|
||||
desc: The toggle itself
|
||||
- class: accordion-body
|
||||
desc: Panel revealed when the section opens
|
||||
style:
|
||||
- class: accordion-button-toggle
|
||||
desc: Chevron indicator on the toggle
|
||||
- class: accordion-button-toggle-plus
|
||||
desc: Plus and minus indicator instead of a chevron
|
||||
modifier:
|
||||
- class: accordion-flush
|
||||
desc: Removes the outer border and rounding, to sit flush in a parent
|
||||
- class: accordion-inverted
|
||||
desc: Moves the toggle indicator to the start of the header
|
||||
- class: accordion-tabs
|
||||
desc: Styles the headers as a row of tabs
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
import Icon from '@ui/Icon.astro';
|
||||
@@ -17,7 +43,32 @@ Accordion interaction uses Bootstrap Collapse. Add `data-bs-toggle="collapse"` a
|
||||
This preview shows the base structure with one expanded section.
|
||||
|
||||
<Example>
|
||||
<div class="accordion" id="accordion-overview"> <div class="accordion-item"> <h2 class="accordion-header"> <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#overview-item-1" aria-expanded="true" aria-controls="overview-item-1" > Account details <span class="accordion-button-toggle"> <Icon name="chevron-down" /> </span> </button> </h2> <div id="overview-item-1" class="accordion-collapse collapse show" data-bs-parent="#accordion-overview"> <div class="accordion-body"> Update profile fields, contact details, and team role settings in this section. </div> </div> </div> <div class="accordion-item"> <h2 class="accordion-header"> <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#overview-item-2" aria-expanded="false" aria-controls="overview-item-2" > Security settings <span class="accordion-button-toggle"> <Icon name="chevron-down" /> </span> </button> </h2> <div id="overview-item-2" class="accordion-collapse collapse" data-bs-parent="#accordion-overview"> <div class="accordion-body"> Configure password policy, two-factor requirements, and active device sessions. </div> </div> </div> <div class="accordion-item"> <h2 class="accordion-header"> <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#overview-item-3" aria-expanded="false" aria-controls="overview-item-3" > Notification preferences <span class="accordion-button-toggle"> <Icon name="chevron-down" /> </span> </button> </h2> <div id="overview-item-3" class="accordion-collapse collapse" data-bs-parent="#accordion-overview"> <div class="accordion-body"> Choose which updates to receive by email, browser push, and weekly digest. You can set separate rules for account alerts and product announcements. </div> </div> </div> </div>
|
||||
<div class="accordion" id="accordion-overview">
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header">
|
||||
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#overview-item-1" aria-expanded="true" aria-controls="overview-item-1"> Account details <span class="accordion-button-toggle"><Icon name="chevron-down" /></span> </button>
|
||||
</h2>
|
||||
<div id="overview-item-1" class="accordion-collapse collapse show" data-bs-parent="#accordion-overview">
|
||||
<div class="accordion-body"> Update profile fields, contact details, and team role settings in this section. </div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#overview-item-2" aria-expanded="false" aria-controls="overview-item-2"> Security settings <span class="accordion-button-toggle"><Icon name="chevron-down" /></span> </button>
|
||||
</h2>
|
||||
<div id="overview-item-2" class="accordion-collapse collapse" data-bs-parent="#accordion-overview">
|
||||
<div class="accordion-body"> Configure password policy, two-factor requirements, and active device sessions. </div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#overview-item-3" aria-expanded="false" aria-controls="overview-item-3"> Notification preferences <span class="accordion-button-toggle"><Icon name="chevron-down" /></span> </button>
|
||||
</h2>
|
||||
<div id="overview-item-3" class="accordion-collapse collapse" data-bs-parent="#accordion-overview">
|
||||
<div class="accordion-body"> Choose which updates to receive by email, browser push, and weekly digest. You can set separate rules for account alerts and product announcements. </div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Variants
|
||||
@@ -27,7 +78,16 @@ This preview shows the base structure with one expanded section.
|
||||
Use `.accordion-button-toggle-plus` to hide the first SVG path when expanded. This pattern is useful for plus-to-minus toggles.
|
||||
|
||||
<Example>
|
||||
<div class="accordion" id="accordion-plus"> <div class="accordion-item"> <h2 class="accordion-header"> <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#plus-item-1" aria-expanded="true" aria-controls="plus-item-1" > Billing details <span class="accordion-button-toggle accordion-button-toggle-plus"> <svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M12 5v14"></path> <path d="M5 12h14"></path> </svg> </span> </button> </h2> <div id="plus-item-1" class="accordion-collapse collapse show" data-bs-parent="#accordion-plus"> <div class="accordion-body"> View invoices, payment method status, and tax details. </div> </div> </div> </div>
|
||||
<div class="accordion" id="accordion-plus">
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header">
|
||||
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#plus-item-1" aria-expanded="true" aria-controls="plus-item-1"> Billing details <span class="accordion-button-toggle accordion-button-toggle-plus"> <Icon name="plus" /> </span> </button>
|
||||
</h2>
|
||||
<div id="plus-item-1" class="accordion-collapse collapse show" data-bs-parent="#accordion-plus">
|
||||
<div class="accordion-body">View invoices, payment method status, and tax details.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
### With leading icon
|
||||
@@ -35,7 +95,19 @@ Use `.accordion-button-toggle-plus` to hide the first SVG path when expanded. Th
|
||||
Use `.accordion-button-icon` when a row needs a small icon before the label. The icon color uses the secondary token.
|
||||
|
||||
<Example>
|
||||
<div class="accordion" id="accordion-icon"> <div class="accordion-item"> <h2 class="accordion-header"> <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#icon-item-1" aria-expanded="true" aria-controls="icon-item-1" > <span class="accordion-button-icon"> <Icon name="user" /> </span> Team profile <span class="accordion-button-toggle"> <Icon name="chevron-down" /> </span> </button> </h2> <div id="icon-item-1" class="accordion-collapse collapse show" data-bs-parent="#accordion-icon"> <div class="accordion-body"> Manage member names, avatars, and workspace profile details. </div> </div> </div> </div>
|
||||
<div class="accordion" id="accordion-icon">
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header">
|
||||
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#icon-item-1" aria-expanded="true" aria-controls="icon-item-1">
|
||||
<span class="accordion-button-icon"><Icon name="user" /></span> Team profile
|
||||
<span class="accordion-button-toggle"><Icon name="chevron-down" /></span>
|
||||
</button>
|
||||
</h2>
|
||||
<div id="icon-item-1" class="accordion-collapse collapse show" data-bs-parent="#accordion-icon">
|
||||
<div class="accordion-body">Manage member names, avatars, and workspace profile details.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
### Flush accordion
|
||||
@@ -43,7 +115,24 @@ Use `.accordion-button-icon` when a row needs a small icon before the label. The
|
||||
Use `.accordion-flush` to remove side borders and border radius. The first and last items also remove top and bottom borders.
|
||||
|
||||
<Example>
|
||||
<div class="accordion accordion-flush" id="accordion-flush"> <div class="accordion-item"> <h2 class="accordion-header"> <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#flush-item-1" aria-expanded="true" aria-controls="flush-item-1" > API access <span class="accordion-button-toggle"> <Icon name="chevron-down" /> </span> </button> </h2> <div id="flush-item-1" class="accordion-collapse collapse show" data-bs-parent="#accordion-flush"> <div class="accordion-body"> Generate tokens and control access scopes. </div> </div> </div> <div class="accordion-item"> <h2 class="accordion-header"> <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#flush-item-2" aria-expanded="false" aria-controls="flush-item-2" > Webhooks <span class="accordion-button-toggle"> <Icon name="chevron-down" /> </span> </button> </h2> <div id="flush-item-2" class="accordion-collapse collapse" data-bs-parent="#accordion-flush"> <div class="accordion-body"> Manage delivery URLs, retry policy, and event subscriptions. </div> </div> </div> </div>
|
||||
<div class="accordion accordion-flush" id="accordion-flush">
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header">
|
||||
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#flush-item-1" aria-expanded="true" aria-controls="flush-item-1"> API access <span class="accordion-button-toggle"><Icon name="chevron-down" /></span> </button>
|
||||
</h2>
|
||||
<div id="flush-item-1" class="accordion-collapse collapse show" data-bs-parent="#accordion-flush">
|
||||
<div class="accordion-body">Generate tokens and control access scopes.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#flush-item-2" aria-expanded="false" aria-controls="flush-item-2"> Webhooks <span class="accordion-button-toggle"><Icon name="chevron-down" /></span> </button>
|
||||
</h2>
|
||||
<div id="flush-item-2" class="accordion-collapse collapse" data-bs-parent="#accordion-flush">
|
||||
<div class="accordion-body">Manage delivery URLs, retry policy, and event subscriptions.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Examples
|
||||
@@ -53,7 +142,24 @@ Use `.accordion-flush` to remove side borders and border radius. The first and l
|
||||
Use `.accordion-tabs` to add a gap between items and keep full borders around each item. This style works well for settings pages.
|
||||
|
||||
<Example>
|
||||
<div class="accordion accordion-tabs" id="accordion-tabs"> <div class="accordion-item"> <h2 class="accordion-header"> <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#tabs-item-1" aria-expanded="true" aria-controls="tabs-item-1" > Workspace <span class="accordion-button-toggle"> <Icon name="chevron-down" /> </span> </button> </h2> <div id="tabs-item-1" class="accordion-collapse collapse show" data-bs-parent="#accordion-tabs"> <div class="accordion-body"> Configure workspace name, slug, and timezone. </div> </div> </div> <div class="accordion-item"> <h2 class="accordion-header"> <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#tabs-item-2" aria-expanded="false" aria-controls="tabs-item-2" > Notifications <span class="accordion-button-toggle"> <Icon name="chevron-down" /> </span> </button> </h2> <div id="tabs-item-2" class="accordion-collapse collapse" data-bs-parent="#accordion-tabs"> <div class="accordion-body"> Control email, push, and digest notification preferences. </div> </div> </div> </div>
|
||||
<div class="accordion accordion-tabs" id="accordion-tabs">
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header">
|
||||
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#tabs-item-1" aria-expanded="true" aria-controls="tabs-item-1"> Workspace <span class="accordion-button-toggle"><Icon name="chevron-down" /></span> </button>
|
||||
</h2>
|
||||
<div id="tabs-item-1" class="accordion-collapse collapse show" data-bs-parent="#accordion-tabs">
|
||||
<div class="accordion-body">Configure workspace name, slug, and timezone.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#tabs-item-2" aria-expanded="false" aria-controls="tabs-item-2"> Notifications <span class="accordion-button-toggle"><Icon name="chevron-down" /></span> </button>
|
||||
</h2>
|
||||
<div id="tabs-item-2" class="accordion-collapse collapse" data-bs-parent="#accordion-tabs">
|
||||
<div class="accordion-body">Control email, push, and digest notification preferences.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
### Inverted toggle position
|
||||
@@ -61,7 +167,16 @@ Use `.accordion-tabs` to add a gap between items and keep full borders around ea
|
||||
Use `.accordion-inverted` to move the toggle to the start of the button row. This helps layouts where controls should appear before text.
|
||||
|
||||
<Example>
|
||||
<div class="accordion accordion-inverted" id="accordion-inverted"> <div class="accordion-item"> <h2 class="accordion-header"> <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#inverted-item-1" aria-expanded="true" aria-controls="inverted-item-1" > Access policy <span class="accordion-button-toggle"> <Icon name="chevron-down" /> </span> </button> </h2> <div id="inverted-item-1" class="accordion-collapse collapse show" data-bs-parent="#accordion-inverted"> <div class="accordion-body"> Set default policy, invite flow, and sign-in restrictions. </div> </div> </div> </div>
|
||||
<div class="accordion accordion-inverted" id="accordion-inverted">
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header">
|
||||
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#inverted-item-1" aria-expanded="true" aria-controls="inverted-item-1"> Access policy <span class="accordion-button-toggle"><Icon name="chevron-down" /></span> </button>
|
||||
</h2>
|
||||
<div id="inverted-item-1" class="accordion-collapse collapse show" data-bs-parent="#accordion-inverted">
|
||||
<div class="accordion-body">Set default policy, invite flow, and sign-in restrictions.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Accessibility
|
||||
|
||||
@@ -3,10 +3,39 @@ title: Alert
|
||||
summary: An alert message is used to inform users about the status of their action and help them solve problems that may occur. Good alert design is important for the overall user experience of a website or app.
|
||||
description: Show alert messages that inform users about success, info, warning, or danger states, with icons, links, and dismissible options.
|
||||
related: [/ui/components/toast]
|
||||
source: core/scss/ui/_alerts.scss
|
||||
classnames:
|
||||
component:
|
||||
- class: alert
|
||||
desc: Container element
|
||||
part:
|
||||
- class: alert-heading
|
||||
desc: Title line above the message
|
||||
- class: alert-description
|
||||
desc: Secondary text under the title
|
||||
- class: alert-icon
|
||||
desc: Icon slot, sized and colored with the alert
|
||||
- class: alert-link
|
||||
desc: Link inside the message, matched to the alert color
|
||||
- class: alert-action
|
||||
desc: Underlined link on its own line, for the next step
|
||||
- class: alert-list
|
||||
desc: List inside the alert, with the default list margin removed
|
||||
style:
|
||||
- class: alert-important
|
||||
desc: Solid fill in the alert color, with white text
|
||||
- class: alert-minor
|
||||
desc: Drops the tinted background, keeps a plain border
|
||||
- class: alert-dismissible
|
||||
desc: Reserves room on the trailing edge for the close button
|
||||
color:
|
||||
- class: alert-{color}
|
||||
desc: Any base color, for example alert-success, alert-blue or alert-muted
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
import CodeDocs from '@components/CodeDocs.astro';
|
||||
import Alert from '@ui/Alert.astro';
|
||||
import Icon from '@ui/Icon.astro'
|
||||
|
||||
## Default markup
|
||||
|
||||
@@ -28,6 +57,46 @@ Add a link to your alert message to redirect users to the details they need to c
|
||||
<Alert color="danger" title="This is a danger alert" link="check it out" />
|
||||
</Example>
|
||||
|
||||
Use `alert-action` instead when the link is the thing to do next rather than a word inside a sentence. It is underlined on its own line and drops the underline on hover.
|
||||
|
||||
<Example>
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<h4 class="alert-heading">An error occurred</h4>
|
||||
<div class="text-secondary">We could not save your changes.</div>
|
||||
<a href="#" class="alert-action">Try again</a>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Alert with a list
|
||||
|
||||
Wrap several messages in a `ul` with the `alert-list` class. It removes the default list margin so the items sit flush inside the alert.
|
||||
|
||||
<Example>
|
||||
<div class="alert alert-warning" role="alert">
|
||||
<h4 class="alert-heading">Check these fields</h4>
|
||||
<ul class="alert-list">
|
||||
<li>The email address is missing.</li>
|
||||
<li>The password is too short.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Minor alerts
|
||||
|
||||
Add `alert-minor` for a quieter alert. It drops the tinted background and keeps a plain border, so the color only shows in the icon and the heading. Use it where an alert would otherwise dominate the page.
|
||||
|
||||
<Example>
|
||||
<div class="alert alert-minor alert-info alert-dismissible" role="alert">
|
||||
<div class="alert-heading">Did you know?</div>
|
||||
<div class="text-secondary">Here is something that you might like to know.</div>
|
||||
<a class="btn-close" data-bs-dismiss="alert" aria-label="close"></a>
|
||||
</div>
|
||||
<div class="alert alert-minor alert-success" role="alert">
|
||||
<div class="alert-heading">Everything worked</div>
|
||||
<div class="text-secondary">Your account has been saved.</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Dismissible alerts
|
||||
|
||||
Add the `x` close button to make an alert modal dismissible. Thanks to that, your alert modal will disappear only when the user closes it.
|
||||
@@ -47,7 +116,59 @@ Add an icon to your alert modal to make it more user-friendly and help users eas
|
||||
Use the `alert-icon` class on an `<svg>` (or on an `<i>` when using the webfont) to provide the proper styling.
|
||||
|
||||
<Example>
|
||||
<div class="alert alert-success" role="alert"> <div class="d-flex"> <div> <svg xmlns="http://www.w3.org/2000/svg" class="icon alert-icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" > <path stroke="none" d="M0 0h24v24H0z" fill="none" /> <path d="M5 12l5 5l10 -10" /> </svg> </div> <div> <h4 class="alert-title">Wow! Everything worked!</h4> <div class="text-secondary">Your account has been saved!</div> </div> </div> </div> <div class="alert alert-info" role="alert"> <div class="d-flex"> <div> <svg xmlns="http://www.w3.org/2000/svg" class="icon alert-icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" > <path stroke="none" d="M0 0h24v24H0z" fill="none" /> <circle cx="12" cy="12" r="9" /> <line x1="12" y1="8" x2="12.01" y2="8" /> <polyline points="11 12 12 12 12 16 13 16" /> </svg> </div> <div> <h4 class="alert-title">Did you know?</h4> <div class="text-secondary">Here is something that you might like to know.</div> </div> </div> </div> <div class="alert alert-warning" role="alert"> <div class="d-flex"> <div> <svg xmlns="http://www.w3.org/2000/svg" class="icon alert-icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" > <path stroke="none" d="M0 0h24v24H0z" fill="none" /> <path d="M12 9v2m0 4v.01" /> <path d="M5 19h14a2 2 0 0 0 1.84 -2.75l-7.1 -12.25a2 2 0 0 0 -3.5 0l-7.1 12.25a2 2 0 0 0 1.75 2.75" /> </svg> </div> <div> <h4 class="alert-title">Uh oh, something went wrong</h4> <div class="text-secondary">Sorry! There was a problem with your request.</div> </div> </div> </div> <div class="alert alert-danger" role="alert"> <div class="d-flex"> <div> <svg xmlns="http://www.w3.org/2000/svg" class="icon alert-icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" > <path stroke="none" d="M0 0h24v24H0z" fill="none" /> <circle cx="12" cy="12" r="9" /> <line x1="12" y1="8" x2="12" y2="12" /> <line x1="12" y1="16" x2="12.01" y2="16" /> </svg> </div> <div> <h4 class="alert-title">I'm so sorry…</h4> <div class="text-secondary">Your account has been deleted and can't be restored.</div> </div> </div> </div>
|
||||
<div class="alert alert-success" role="alert">
|
||||
<div class="d-flex">
|
||||
<div>
|
||||
<Icon name="check" class="alert-icon" />
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="alert-heading">Wow! Everything worked!</h4>
|
||||
<div class="text-secondary">Your account has been saved!</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert alert-info" role="alert">
|
||||
<div class="d-flex">
|
||||
<div>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon alert-icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<circle cx="12" cy="12" r="9" />
|
||||
<line x1="12" y1="8" x2="12.01" y2="8" />
|
||||
<polyline points="11 12 12 12 12 16 13 16" />
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="alert-heading">Did you know?</h4>
|
||||
<div class="text-secondary">Here is something that you might like to know.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert alert-warning" role="alert">
|
||||
<div class="d-flex">
|
||||
<div>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon alert-icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M12 9v2m0 4v.01" />
|
||||
<path d="M5 19h14a2 2 0 0 0 1.84 -2.75l-7.1 -12.25a2 2 0 0 0 -3.5 0l-7.1 12.25a2 2 0 0 0 1.75 2.75" />
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="alert-heading">Uh oh, something went wrong</h4>
|
||||
<div class="text-secondary">Sorry! There was a problem with your request.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<div class="d-flex">
|
||||
<div>
|
||||
<Icon name="alert-circle" class="alert-icon" />
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="alert-heading">I'm so sorry…</h4>
|
||||
<div class="text-secondary">Your account has been deleted and can't be restored.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Alert with avatar
|
||||
@@ -55,7 +176,36 @@ Use the `alert-icon` class on an `<svg>` (or on an `<i>` when using the webfont)
|
||||
Add an [avatar](/ui/components/avatar) to your alert modal to make it more personalized.
|
||||
|
||||
<Example>
|
||||
<div class="alert alert-success" role="alert"> <div class="d-flex"> <div> <span class="avatar me-3" style="background-image: url(/static/avatars/039m.jpg)" ></span> </div> <div> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Lorem ipsum dolor sit amet, consectetur adipisicing elit. </div> </div> </div> <div class="alert alert-info" role="alert"> <div class="d-flex"> <div> <span class="avatar me-3">JL</span> </div> <div> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Lorem ipsum dolor sit amet, consectetur adipisicing elit. </div> </div> </div> <div class="alert alert-warning" role="alert"> <div class="d-flex"> <div> <span class="avatar me-3" style="background-image: url(/static/avatars/035f.jpg)" ></span> </div> <div> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Lorem ipsum dolor sit amet, consectetur adipisicing elit. </div> </div> </div> <div class="alert alert-danger" role="alert"> <div class="d-flex"> <div> <span class="avatar me-3" style="background-image: url(/static/avatars/056f.jpg)" ></span> </div> <div> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Lorem ipsum dolor sit amet, consectetur adipisicing elit. </div> </div> </div>
|
||||
<div class="alert alert-success" role="alert">
|
||||
<div class="d-flex">
|
||||
<div>
|
||||
<span class="avatar me-3" style="background-image: url(/static/avatars/039m.jpg)"></span>
|
||||
</div>
|
||||
<div> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Lorem ipsum dolor sit amet, consectetur adipisicing elit. </div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert alert-info" role="alert">
|
||||
<div class="d-flex">
|
||||
<div><span class="avatar me-3">JL</span></div>
|
||||
<div> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Lorem ipsum dolor sit amet, consectetur adipisicing elit. </div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert alert-warning" role="alert">
|
||||
<div class="d-flex">
|
||||
<div>
|
||||
<span class="avatar me-3" style="background-image: url(/static/avatars/035f.jpg)"></span>
|
||||
</div>
|
||||
<div> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Lorem ipsum dolor sit amet, consectetur adipisicing elit. </div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<div class="d-flex">
|
||||
<div>
|
||||
<span class="avatar me-3" style="background-image: url(/static/avatars/056f.jpg)"></span>
|
||||
</div>
|
||||
<div> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Lorem ipsum dolor sit amet, consectetur adipisicing elit. </div>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Alert with buttons
|
||||
@@ -65,7 +215,42 @@ Add primary and secondary [buttons](/ui/components/button) to your alert modals
|
||||
Buttons don't inherit the alert's color, so you should set the proper class if you want it to be matched. For example, `btn-success` for `alert-success`.
|
||||
|
||||
<Example>
|
||||
<div class="alert alert-success alert-dismissible" role="alert"> <h3 class="mb-1">Some Title</h3> <p class="text-secondary"> Lorem ipsum Minim ad pariatur eiusmod ea ut nulla aliqua est quis id dolore minim voluptate. </p> <div class="btn-list"> <a href="#" class="btn btn-success">Okay</a> <a href="#" class="btn">Cancel</a> </div> <a class="btn-close" data-bs-dismiss="alert" aria-label="close"></a> </div> <div class="alert alert-info alert-dismissible" role="alert"> <h3 class="mb-1">Some Title</h3> <p class="text-secondary"> Lorem ipsum Minim ad pariatur eiusmod ea ut nulla aliqua est quis id dolore minim voluptate. </p> <div class="btn-list"> <a href="#" class="btn btn-info">Okay</a> <a href="#" class="btn">Cancel</a> </div> <a class="btn-close" data-bs-dismiss="alert" aria-label="close"></a> </div> <div class="alert alert-warning alert-dismissible" role="alert"> <h3 class="mb-1">Some Title</h3> <p class="text-secondary"> Lorem ipsum Minim ad pariatur eiusmod ea ut nulla aliqua est quis id dolore minim voluptate. </p> <div class="btn-list"> <a href="#" class="btn btn-warning">Okay</a> <a href="#" class="btn">Cancel</a> </div> <a class="btn-close" data-bs-dismiss="alert" aria-label="close"></a> </div> <div class="alert alert-danger alert-dismissible" role="alert"> <h3 class="mb-1">Some Title</h3> <p class="text-secondary"> Lorem ipsum Minim ad pariatur eiusmod ea ut nulla aliqua est quis id dolore minim voluptate. </p> <div class="btn-list"> <a href="#" class="btn btn-danger">Okay</a> <a href="#" class="btn">Cancel</a> </div> <a class="btn-close" data-bs-dismiss="alert" aria-label="close"></a> </div>
|
||||
<div class="alert alert-success alert-dismissible" role="alert">
|
||||
<h3 class="mb-1">Some Title</h3>
|
||||
<p class="text-secondary"> Lorem ipsum Minim ad pariatur eiusmod ea ut nulla aliqua est quis id dolore minim voluptate. </p>
|
||||
<div class="btn-list">
|
||||
<a href="#" class="btn btn-success">Okay</a>
|
||||
<a href="#" class="btn">Cancel</a>
|
||||
</div>
|
||||
<a class="btn-close" data-bs-dismiss="alert" aria-label="close"></a>
|
||||
</div>
|
||||
<div class="alert alert-info alert-dismissible" role="alert">
|
||||
<h3 class="mb-1">Some Title</h3>
|
||||
<p class="text-secondary"> Lorem ipsum Minim ad pariatur eiusmod ea ut nulla aliqua est quis id dolore minim voluptate. </p>
|
||||
<div class="btn-list">
|
||||
<a href="#" class="btn btn-info">Okay</a>
|
||||
<a href="#" class="btn">Cancel</a>
|
||||
</div>
|
||||
<a class="btn-close" data-bs-dismiss="alert" aria-label="close"></a>
|
||||
</div>
|
||||
<div class="alert alert-warning alert-dismissible" role="alert">
|
||||
<h3 class="mb-1">Some Title</h3>
|
||||
<p class="text-secondary"> Lorem ipsum Minim ad pariatur eiusmod ea ut nulla aliqua est quis id dolore minim voluptate. </p>
|
||||
<div class="btn-list">
|
||||
<a href="#" class="btn btn-warning">Okay</a>
|
||||
<a href="#" class="btn">Cancel</a>
|
||||
</div>
|
||||
<a class="btn-close" data-bs-dismiss="alert" aria-label="close"></a>
|
||||
</div>
|
||||
<div class="alert alert-danger alert-dismissible" role="alert">
|
||||
<h3 class="mb-1">Some Title</h3>
|
||||
<p class="text-secondary"> Lorem ipsum Minim ad pariatur eiusmod ea ut nulla aliqua est quis id dolore minim voluptate. </p>
|
||||
<div class="btn-list">
|
||||
<a href="#" class="btn btn-danger">Okay</a>
|
||||
<a href="#" class="btn">Cancel</a>
|
||||
</div>
|
||||
<a class="btn-close" data-bs-dismiss="alert" aria-label="close"></a>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Important alerts
|
||||
@@ -79,17 +264,66 @@ If you want your alert to be really eye-catching, you can add an `alert-importan
|
||||
You can also use other elements, like icons and dismissible buttons, with this type of alert.
|
||||
|
||||
<Example>
|
||||
<div class="alert alert-important alert-success alert-dismissible" role="alert"> <div class="d-flex"> <div> <svg xmlns="http://www.w3.org/2000/svg" class="icon alert-icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" > <path stroke="none" d="M0 0h24v24H0z" fill="none"></path> <path d="M5 12l5 5l10 -10"></path> </svg> </div> <div>Wow! Everything worked!</div> </div> <a class="btn-close btn-close-white" data-bs-dismiss="alert" aria-label="close"></a> </div> <div class="alert alert-important alert-danger alert-dismissible" role="alert"> <div class="d-flex"> <div> <svg xmlns="http://www.w3.org/2000/svg" class="icon alert-icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" > <path stroke="none" d="M0 0h24v24H0z" fill="none" /> <circle cx="12" cy="12" r="9" /> <line x1="12" y1="8" x2="12" y2="12" /> <line x1="12" y1="16" x2="12.01" y2="16" /> </svg> </div> <div>Your account has been deleted and can't be restored.</div> </div> <a class="btn-close btn-close-white" data-bs-dismiss="alert" aria-label="close"></a> </div>
|
||||
<div class="alert alert-important alert-success alert-dismissible" role="alert">
|
||||
<div class="d-flex">
|
||||
<div>
|
||||
<Icon name="check" class="alert-icon" />
|
||||
</div>
|
||||
<div>Wow! Everything worked!</div>
|
||||
</div>
|
||||
<a class="btn-close" data-bs-dismiss="alert" aria-label="close"></a>
|
||||
</div>
|
||||
<div class="alert alert-important alert-danger alert-dismissible" role="alert">
|
||||
<div class="d-flex">
|
||||
<div>
|
||||
<Icon name="alert-circle" class="alert-icon" />
|
||||
</div>
|
||||
<div>Your account has been deleted and can't be restored.</div>
|
||||
</div>
|
||||
<a class="btn-close" data-bs-dismiss="alert" aria-label="close"></a>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Custom alert color
|
||||
|
||||
You're not limited to the 4 default alert colors. You can use any [base or social color](/ui/base/colors) you want.
|
||||
You're not limited to the 4 default alert colors. You can use any [base color](/ui/base/colors) you want.
|
||||
|
||||
<Example>
|
||||
<div class="alert alert-lime" role="alert"> <h4 class="alert-title">Wow! Everything worked!</h4> <div class="text-secondary">Your account has been saved!</div> </div> <div class="alert alert-cyan" role="alert"> <h4 class="alert-title">Did you know?</h4> <div class="text-secondary">Here is something that you might like to know.</div> </div> <div class="alert alert-facebook" role="alert"> <h4 class="alert-title">You have a new friend on Facebook</h4> <div class="text-secondary">Say hello to your new friend!</div> </div> <div class="alert alert-instagram alert-dismissible alert-important" role="alert"> <div class="d-flex"> <div> <span class="avatar me-3" style="background-image: url(/static/avatars/035f.jpg)" ></span> </div> <div> <h4 class="alert-title">Sophia just added a new post on Instagram</h4> <div>Be the first to see it!</div> </div> </div> <a class="btn-close" data-bs-dismiss="alert" aria-label="close"></a> </div>
|
||||
<div class="alert alert-lime" role="alert">
|
||||
<h4 class="alert-heading">Wow! Everything worked!</h4>
|
||||
<div class="text-secondary">Your account has been saved!</div>
|
||||
</div>
|
||||
<div class="alert alert-cyan" role="alert">
|
||||
<h4 class="alert-heading">Did you know?</h4>
|
||||
<div class="text-secondary">Here is something that you might like to know.</div>
|
||||
</div>
|
||||
<div class="alert alert-blue" role="alert">
|
||||
<h4 class="alert-heading">You have a new friend on Facebook</h4>
|
||||
<div class="text-secondary">Say hello to your new friend!</div>
|
||||
</div>
|
||||
<div class="alert alert-pink alert-dismissible alert-important" role="alert">
|
||||
<div class="d-flex">
|
||||
<div>
|
||||
<span class="avatar me-3" style="background-image: url(/static/avatars/035f.jpg)"></span>
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="alert-heading">Sophia just added a new post on Instagram</h4>
|
||||
<div>Be the first to see it!</div>
|
||||
</div>
|
||||
</div>
|
||||
<a class="btn-close" data-bs-dismiss="alert" aria-label="close"></a>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Accessibility
|
||||
|
||||
- Give an alert a role that matches how urgent it is. `role="alert"` interrupts the screen reader and suits an error; `role="status"` waits for a pause and suits a confirmation.
|
||||
- The live region has to exist before the message arrives. Render the container on page load and put the text into it, rather than inserting the whole alert at the moment of the event.
|
||||
- Label the dismiss button with `aria-label="Close"`. `btn-close` has no text of its own.
|
||||
- The icon is decoration, so the alert must still read correctly with the icon ignored. Keep the meaning in the heading and the text.
|
||||
- Colour alone does not say "error". A red alert and a green one must differ in their words too.
|
||||
- After dismissing an alert, move focus somewhere sensible. Focus left on a removed element falls back to the top of the page.
|
||||
|
||||
## SCSS variables
|
||||
|
||||
Use these SCSS variables to customize alerts. The default values are:
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
---
|
||||
title: Autosize
|
||||
summary: The autosize element will automatically adjust the textarea height and make it easier for users to follow as they type.
|
||||
docs-libs: [autosize]
|
||||
description: Make textareas grow automatically as users type with the autosize plugin, so longer text stays visible without manual resizing.
|
||||
related: [/ui/forms/form-elements]
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
import CodeDocs from '@components/CodeDocs.astro';
|
||||
|
||||
To be able to use the autosize in your application you will need to install the autosize dependency with `npm install autosize`.
|
||||
|
||||
## Default markup
|
||||
|
||||
Add the autosize element to your input to make it automatically adjust to the length of a text as a user types it.
|
||||
|
||||
To create autosize textarea, add the `data-bs-toggle="autosize"` attribute to the textarea element:
|
||||
|
||||
<Example column vertical>
|
||||
<label class="form-label">Autosize example</label> <textarea class="form-control" data-bs-toggle="autosize" placeholder="Type something…"></textarea>
|
||||
</Example>
|
||||
|
||||
## JavaScript
|
||||
|
||||
Tabler automatically initializes all elements with `data-bs-toggle="autosize"` on page load. This is the code that runs:
|
||||
|
||||
<CodeDocs name="autosize-init" file="core/js/src/autosize.ts" />
|
||||
@@ -3,6 +3,36 @@ title: Avatar
|
||||
summary: An avatar helps customize interface elements and make the product experience more personalized. It is often used in communication apps, collaboration tools, and social media.
|
||||
description: Display user avatars with images, initials, or icons. Change sizes, shapes, and colors, or group them into stacked avatar lists.
|
||||
related: [/ui/components/status, /ui/components/badge]
|
||||
source: core/scss/ui/_avatars.scss
|
||||
classnames:
|
||||
component:
|
||||
- class: avatar
|
||||
desc: Container element
|
||||
part:
|
||||
- class: avatar-brand
|
||||
desc: Small brand mark in the bottom corner
|
||||
- class: avatar-cover
|
||||
desc: Pulls the avatar over the element above it, with a ring
|
||||
- class: avatar-upload-text
|
||||
desc: Label inside an empty upload slot
|
||||
- class: avatar-list
|
||||
desc: Wrapper that spaces several avatars in a row
|
||||
style:
|
||||
- class: avatar-square
|
||||
desc: Rounded corners instead of a circle
|
||||
- class: avatar-rounded
|
||||
desc: Fully round, the default shape
|
||||
- class: avatar-upload
|
||||
desc: Dashed empty slot for a picture that is not set yet
|
||||
modifier:
|
||||
- class: avatar-list-stacked
|
||||
desc: Overlaps the avatars in the list
|
||||
color:
|
||||
- class: bg-{color}
|
||||
desc: Any base color for an avatar with initials, for example bg-azure-lt
|
||||
size:
|
||||
- class: avatar-{size}
|
||||
desc: From avatar-xxs to avatar-2xl; avatar-list-{size} sizes a whole list
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
import Icon from '@ui/Icon.astro';
|
||||
@@ -14,7 +44,11 @@ import CodeDocs from '@components/CodeDocs.astro';
|
||||
Use the `avatar` class to add an avatar to your interface design for greater customization.
|
||||
|
||||
<Example centered>
|
||||
<AvatarList> <span class="avatar" style="background-image: url(/static/avatars/002f.jpg)"></span> <span class="avatar">JL</span> <span class="avatar" style="background-image: url(/static/avatars/004f.jpg)"></span> </AvatarList>
|
||||
<AvatarList>
|
||||
<span class="avatar" style="background-image: url(/static/avatars/002f.jpg)"></span>
|
||||
<span class="avatar">JL</span>
|
||||
<span class="avatar" style="background-image: url(/static/avatars/004f.jpg)"></span>
|
||||
</AvatarList>
|
||||
</Example>
|
||||
|
||||
## Avatar image
|
||||
@@ -22,7 +56,11 @@ Use the `avatar` class to add an avatar to your interface design for greater cus
|
||||
Set an image as the background to make users easy to indentify and create a personalized experience.
|
||||
|
||||
<Example centered>
|
||||
<AvatarList> <span class="avatar" style="background-image: url(/static/avatars/016f.jpg)"></span> <span class="avatar" style="background-image: url(/static/avatars/022m.jpg)"></span> <span class="avatar" style="background-image: url(/static/avatars/036m.jpg)"></span> </AvatarList>
|
||||
<AvatarList>
|
||||
<span class="avatar" style="background-image: url(/static/avatars/016f.jpg)"></span>
|
||||
<span class="avatar" style="background-image: url(/static/avatars/022m.jpg)"></span>
|
||||
<span class="avatar" style="background-image: url(/static/avatars/036m.jpg)"></span>
|
||||
</AvatarList>
|
||||
</Example>
|
||||
|
||||
## Initials
|
||||
@@ -30,7 +68,13 @@ Set an image as the background to make users easy to indentify and create a pers
|
||||
You can also use initials instead of pictures.
|
||||
|
||||
<Example centered>
|
||||
<AvatarList> <span class="avatar">AB</span> <span class="avatar">CD</span> <span class="avatar">EF</span> <span class="avatar">GH</span> <span class="avatar">IJ</span> </AvatarList>
|
||||
<AvatarList>
|
||||
<span class="avatar">AB</span>
|
||||
<span class="avatar">CD</span>
|
||||
<span class="avatar">EF</span>
|
||||
<span class="avatar">GH</span>
|
||||
<span class="avatar">IJ</span>
|
||||
</AvatarList>
|
||||
</Example>
|
||||
|
||||
## Avatar icons
|
||||
@@ -38,7 +82,11 @@ You can also use initials instead of pictures.
|
||||
Besides pictures and initials, you can also use [icons](/ui/components/icon) to make the avatars more universal.
|
||||
|
||||
<Example centered>
|
||||
<AvatarList> <span class="avatar"> <Icon name="user" /> </span> <span class="avatar"> <Icon name="plus" /> </span> <span class="avatar"> <Icon name="settings" /> </span> </AvatarList>
|
||||
<AvatarList>
|
||||
<span class="avatar"><Icon name="user" /></span>
|
||||
<span class="avatar"><Icon name="plus" /></span>
|
||||
<span class="avatar"><Icon name="settings" /></span>
|
||||
</AvatarList>
|
||||
</Example>
|
||||
|
||||
## Avatar initials color
|
||||
@@ -46,7 +94,13 @@ Besides pictures and initials, you can also use [icons](/ui/components/icon) to
|
||||
Customize the color of the avatars' background. See the [full list of available colors](/ui/base/colors) for more details.
|
||||
|
||||
<Example centered>
|
||||
<AvatarList> <span class="avatar bg-green-lt">AB</span> <span class="avatar bg-red-lt">CD</span> <span class="avatar bg-yellow-lt">EF</span> <span class="avatar bg-primary-lt">GH</span> <span class="avatar bg-purple-lt">IJ</span> </AvatarList>
|
||||
<AvatarList>
|
||||
<span class="avatar bg-green-lt">AB</span>
|
||||
<span class="avatar bg-red-lt">CD</span>
|
||||
<span class="avatar bg-yellow-lt">EF</span>
|
||||
<span class="avatar bg-primary-lt">GH</span>
|
||||
<span class="avatar bg-purple-lt">IJ</span>
|
||||
</AvatarList>
|
||||
</Example>
|
||||
|
||||
## Avatar size
|
||||
@@ -54,7 +108,13 @@ Customize the color of the avatars' background. See the [full list of available
|
||||
Using Bootstrap’s typical naming structure, you can create a standard avatar or scale it up or down to different sizes based on what you need.
|
||||
|
||||
<Example centered>
|
||||
<AvatarList> <span class="avatar avatar-xl" style="background-image: url(/static/avatars/000m.jpg)"></span> <span class="avatar avatar-lg" style="background-image: url(/static/avatars/000m.jpg)"></span> <span class="avatar" style="background-image: url(/static/avatars/000m.jpg)"></span> <span class="avatar avatar-sm" style="background-image: url(/static/avatars/000m.jpg)"></span> <span class="avatar avatar-xs" style="background-image: url(/static/avatars/000m.jpg)"></span> </AvatarList>
|
||||
<AvatarList>
|
||||
<span class="avatar avatar-xl" style="background-image: url(/static/avatars/000m.jpg)"></span>
|
||||
<span class="avatar avatar-lg" style="background-image: url(/static/avatars/000m.jpg)"></span>
|
||||
<span class="avatar" style="background-image: url(/static/avatars/000m.jpg)"></span>
|
||||
<span class="avatar avatar-sm" style="background-image: url(/static/avatars/000m.jpg)"></span>
|
||||
<span class="avatar avatar-xs" style="background-image: url(/static/avatars/000m.jpg)"></span>
|
||||
</AvatarList>
|
||||
</Example>
|
||||
|
||||
## Avatar status
|
||||
@@ -62,15 +122,78 @@ Using Bootstrap’s typical naming structure, you can create a standard avatar o
|
||||
Add a [status indicator](/ui/components/status) to your avatar to show, for instance, if a user is online or offline or indicate the number of messages they have received.
|
||||
|
||||
<Example centered>
|
||||
<AvatarList> <span class="avatar" style="background-image: url(/static/avatars/018m.jpg)"></span> <span class="avatar" style="background-image: url(/static/avatars/015m.jpg)"> <span class="badge bg-danger"></span> </span> <span class="avatar" style="background-image: url(/static/avatars/022m.jpg)"> <span class="badge bg-success"></span> </span> <span class="avatar"> <span class="badge bg-warning"></span>SA </span> <span class="avatar" style="background-image: url(/static/avatars/022m.jpg)"> <span class="badge bg-info"></span> </span> <span class="avatar" style="background-image: url(/static/avatars/048m.jpg)"> <span class="badge bg-gray">5</span> </span> </AvatarList>
|
||||
<AvatarList>
|
||||
<span class="avatar" style="background-image: url(/static/avatars/018m.jpg)"></span>
|
||||
<span class="avatar" style="background-image: url(/static/avatars/015m.jpg)">
|
||||
<span class="badge bg-danger"></span>
|
||||
</span>
|
||||
<span class="avatar" style="background-image: url(/static/avatars/022m.jpg)">
|
||||
<span class="badge bg-success"></span>
|
||||
</span>
|
||||
<span class="avatar">
|
||||
<span class="badge bg-warning"></span> SA
|
||||
</span>
|
||||
<span class="avatar" style="background-image: url(/static/avatars/022m.jpg)">
|
||||
<span class="badge bg-info"></span>
|
||||
</span>
|
||||
<span class="avatar" style="background-image: url(/static/avatars/048m.jpg)">
|
||||
<span class="badge bg-gray-500">5</span>
|
||||
</span>
|
||||
</AvatarList>
|
||||
</Example>
|
||||
|
||||
## Avatar shape
|
||||
|
||||
Change the shape of an avatar with the default Bootstrap image classes. You can make them round or square and change their border radius.
|
||||
An avatar is a circle by default. Add `avatar-square` to give it the same rounded corners as the rest of the interface - the usual choice when the avatar stands for a company, a project or an app rather than a person.
|
||||
|
||||
<Example centered>
|
||||
<AvatarList> <span class="avatar" style="background-image: url(/static/avatars/019m.jpg)"></span> <span class="avatar rounded" style="background-image: url(/static/avatars/039f.jpg)"></span> <span class="avatar rounded-circle">AA</span> <span class="avatar rounded-0" style="background-image: url(/static/avatars/043f.jpg)"></span> <span class="avatar rounded-3" style="background-image: url(/static/avatars/044f.jpg)"></span> </AvatarList>
|
||||
<AvatarList>
|
||||
<span class="avatar" style="background-image: url(/static/avatars/019m.jpg)"></span>
|
||||
<span class="avatar avatar-square" style="background-image: url(/static/avatars/039f.jpg)"></span>
|
||||
<span class="avatar avatar-square bg-primary text-white">TB</span>
|
||||
<span class="avatar avatar-square bg-green-lt">AA</span>
|
||||
</AvatarList>
|
||||
</Example>
|
||||
|
||||
For any other radius use the Bootstrap utilities. `rounded-0` gives sharp corners, and `rounded-3` a larger radius than `avatar-square`.
|
||||
|
||||
<Example centered>
|
||||
<AvatarList>
|
||||
<span class="avatar rounded-0" style="background-image: url(/static/avatars/043f.jpg)"></span>
|
||||
<span class="avatar rounded-3" style="background-image: url(/static/avatars/044f.jpg)"></span>
|
||||
</AvatarList>
|
||||
</Example>
|
||||
|
||||
## Avatar brand
|
||||
|
||||
Add a `avatar-brand` element inside an avatar to mark where the account comes from. It sits in the bottom corner and keeps its own background, so a brand logo stays readable over any photo.
|
||||
|
||||
<Example centered>
|
||||
<AvatarList>
|
||||
<span class="avatar" style="background-image: url(/static/avatars/000m.jpg)">
|
||||
<span class="avatar-brand" style="background-image: url(/static/brands/github.svg)"></span>
|
||||
</span>
|
||||
<span class="avatar" style="background-image: url(/static/avatars/002m.jpg)">
|
||||
<span class="avatar-brand" style="background-image: url(/static/brands/google.svg)"></span>
|
||||
</span>
|
||||
</AvatarList>
|
||||
</Example>
|
||||
|
||||
## Avatar on a cover
|
||||
|
||||
Add `avatar-cover` to pull an avatar halfway over the element above it and draw a ring in the card background color. Use it for a profile picture that overlaps a cover image.
|
||||
|
||||
<Example>
|
||||
<div class="card" style="max-width: 20rem">
|
||||
<div class="card-body p-0">
|
||||
<div class="bg-primary-lt" style="height: 5rem"></div>
|
||||
<div class="text-center p-3">
|
||||
<span class="avatar avatar-xl avatar-cover rounded-circle mb-3" style="background-image: url(/static/avatars/039f.jpg)"></span>
|
||||
<div class="fw-medium">Paweł Kuna</div>
|
||||
<div class="text-secondary">UI Designer</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Avatar upload
|
||||
@@ -80,7 +203,11 @@ Use the `avatar-upload` class together with `avatar` to show an empty avatar slo
|
||||
Put an icon inside to show the action. The variant is often used as a link or a button.
|
||||
|
||||
<Example centered>
|
||||
<AvatarList> <a href="#" class="avatar avatar-upload"> <Icon name="plus" /> </a> <a href="#" class="avatar avatar-upload rounded"> <Icon name="plus" /> </a> <a href="#" class="avatar avatar-upload rounded-0"> <Icon name="camera" /> </a> </AvatarList>
|
||||
<AvatarList>
|
||||
<a href="#" class="avatar avatar-upload"><Icon name="plus" /></a>
|
||||
<a href="#" class="avatar avatar-upload rounded"><Icon name="plus" /></a>
|
||||
<a href="#" class="avatar avatar-upload rounded-0"><Icon name="camera" /></a>
|
||||
</AvatarList>
|
||||
</Example>
|
||||
|
||||
## Avatar upload size
|
||||
@@ -88,7 +215,13 @@ Put an icon inside to show the action. The variant is often used as a link or a
|
||||
The upload avatar uses the same size classes as a normal avatar, from `avatar-xxs` to `avatar-2xl`.
|
||||
|
||||
<Example centered>
|
||||
<AvatarList> <a href="#" class="avatar avatar-upload avatar-2xl rounded"> <Icon name="plus" /> </a> <a href="#" class="avatar avatar-upload avatar-xl rounded"> <Icon name="plus" /> </a> <a href="#" class="avatar avatar-upload avatar-lg rounded"> <Icon name="plus" /> </a> <a href="#" class="avatar avatar-upload rounded"> <Icon name="plus" /> </a> <a href="#" class="avatar avatar-upload avatar-sm rounded"> <Icon name="plus" /> </a> </AvatarList>
|
||||
<AvatarList>
|
||||
<a href="#" class="avatar avatar-upload avatar-2xl rounded"><Icon name="plus" /></a>
|
||||
<a href="#" class="avatar avatar-upload avatar-xl rounded"><Icon name="plus" /></a>
|
||||
<a href="#" class="avatar avatar-upload avatar-lg rounded"><Icon name="plus" /></a>
|
||||
<a href="#" class="avatar avatar-upload rounded"><Icon name="plus" /></a>
|
||||
<a href="#" class="avatar avatar-upload avatar-sm rounded"><Icon name="plus" /></a>
|
||||
</AvatarList>
|
||||
</Example>
|
||||
|
||||
## Avatar upload text
|
||||
@@ -96,7 +229,16 @@ The upload avatar uses the same size classes as a normal avatar, from `avatar-xx
|
||||
Add a short label under the icon with the `avatar-upload-text` class. The content is stacked in a column, so use this only in the larger sizes. The text is shown in uppercase, like all avatar text.
|
||||
|
||||
<Example centered>
|
||||
<AvatarList> <a href="#" class="avatar avatar-upload avatar-xl rounded"> <Icon name="plus" /> <span class="avatar-upload-text">Upload</span> </a> <a href="#" class="avatar avatar-upload avatar-2xl rounded"> <Icon name="camera" /> <span class="avatar-upload-text">Add photo</span> </a> </AvatarList>
|
||||
<AvatarList>
|
||||
<a href="#" class="avatar avatar-upload avatar-xl rounded">
|
||||
<Icon name="plus" />
|
||||
<span class="avatar-upload-text">Upload</span>
|
||||
</a>
|
||||
<a href="#" class="avatar avatar-upload avatar-2xl rounded">
|
||||
<Icon name="camera" />
|
||||
<span class="avatar-upload-text">Add photo</span>
|
||||
</a>
|
||||
</AvatarList>
|
||||
</Example>
|
||||
|
||||
## Avatar upload in a form
|
||||
@@ -104,7 +246,18 @@ Add a short label under the icon with the `avatar-upload-text` class. The conten
|
||||
To pick a real file, use a `label` with the upload classes and connect it to a hidden file input. Add `cursor-pointer`, because the pointer cursor is only set for links.
|
||||
|
||||
<Example>
|
||||
<div class="row align-items-end" style="width: 100%;"> <div class="col-auto"> <label for="avatar-file" class="avatar avatar-upload avatar-lg rounded cursor-pointer"> <Icon name="plus" /> </label> <input type="file" id="avatar-file" class="visually-hidden" accept="image/*" /> </div> <div class="col"> <label class="form-label" for="avatar-file">Avatar</label> <div class="text-secondary">Click to upload a new avatar</div> </div> </div>
|
||||
<div class="row align-items-end" style="width: 100%;">
|
||||
<div class="col-auto">
|
||||
<label for="avatar-file" class="avatar avatar-upload avatar-lg rounded cursor-pointer">
|
||||
<Icon name="plus" />
|
||||
</label>
|
||||
<input type="file" id="avatar-file" class="visually-hidden" accept="image/*" />
|
||||
</div>
|
||||
<div class="col">
|
||||
<label class="form-label" for="avatar-file">Avatar</label>
|
||||
<div class="text-secondary">Click to upload a new avatar</div>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Avatar list
|
||||
@@ -112,7 +265,13 @@ To pick a real file, use a `label` with the upload classes and connect it to a h
|
||||
Use the `.avatar-list` container to create a list of avatars within one parent container. It keeps consistent spacing between items and wraps them when there is not enough space.
|
||||
|
||||
<Example centered>
|
||||
<AvatarList> <span class="avatar rounded" style="background-image: url(/static/avatars/031f.jpg)"></span> <span class="avatar rounded">JL</span> <span class="avatar rounded" style="background-image: url(/static/avatars/033f.jpg)"></span> <span class="avatar rounded" style="background-image: url(/static/avatars/017m.jpg)"></span> <span class="avatar rounded" style="background-image: url(/static/avatars/024m.jpg)"></span> </AvatarList>
|
||||
<AvatarList>
|
||||
<span class="avatar rounded" style="background-image: url(/static/avatars/031f.jpg)"></span>
|
||||
<span class="avatar rounded">JL</span>
|
||||
<span class="avatar rounded" style="background-image: url(/static/avatars/033f.jpg)"></span>
|
||||
<span class="avatar rounded" style="background-image: url(/static/avatars/017m.jpg)"></span>
|
||||
<span class="avatar rounded" style="background-image: url(/static/avatars/024m.jpg)"></span>
|
||||
</AvatarList>
|
||||
</Example>
|
||||
|
||||
## Stacked list
|
||||
|
||||
@@ -3,6 +3,37 @@ title: Badge
|
||||
summary: A badge is a small count and labeling component used to add extra information to an interface element. You can use it to draw user attention to a new element, notify about unread messages, or provide additional context.
|
||||
description: Add badges to show counts, labels, or statuses. Use colors, outline and pill styles, links, and notification dots to add context.
|
||||
related: [/ui/components/status, /ui/components/tag]
|
||||
source: core/scss/ui/_badges.scss
|
||||
classnames:
|
||||
component:
|
||||
- class: badge
|
||||
desc: Container element
|
||||
part:
|
||||
- class: badge-dot
|
||||
desc: Small dot with no text, for a status marker
|
||||
- class: badge-icononly
|
||||
desc: Square badge holding only an icon
|
||||
- class: badge-notification
|
||||
desc: Positions the badge over the corner of its parent
|
||||
- class: badge-list
|
||||
desc: Wrapper that spaces several badges in a row
|
||||
style:
|
||||
- class: badge-outline
|
||||
desc: Transparent fill with a colored border
|
||||
modifier:
|
||||
- class: badge-pill
|
||||
desc: Fully rounded ends
|
||||
behavior:
|
||||
- class: badge-blink
|
||||
desc: Pulsing animation, for a live counter
|
||||
color:
|
||||
- class: bg-{color}
|
||||
desc: Any base color, for example bg-green or bg-red
|
||||
size:
|
||||
- class: badge-sm
|
||||
desc: Small size
|
||||
- class: badge-lg
|
||||
desc: Large size
|
||||
---
|
||||
import BadgeList from '@ui/BadgeList.astro';
|
||||
import Example from '@components/Example.astro';
|
||||
@@ -36,7 +67,12 @@ Use the `.badge-list` container whenever you show more than one badge next to ea
|
||||
Badges can be used in headings to draw attention to new or important information. You can use them in any heading level, from `<h1>` to `<h6>`. The example below shows how to use badges in headings.
|
||||
|
||||
<Example>
|
||||
<h1> Example heading <Badge text="New" /> </h1> <h2> Example heading <Badge text="New" /> </h2> <h3> Example heading <Badge text="New" /> </h3> <h4> Example heading <Badge text="New" /> </h4> <h5> Example heading <Badge text="New" /> </h5> <h6> Example heading <Badge text="New" /> </h6>
|
||||
<h1> Example heading <Badge text="New" /> </h1>
|
||||
<h2> Example heading <Badge text="New" /> </h2>
|
||||
<h3> Example heading <Badge text="New" /> </h3>
|
||||
<h4> Example heading <Badge text="New" /> </h4>
|
||||
<h5> Example heading <Badge text="New" /> </h5>
|
||||
<h6> Example heading <Badge text="New" /> </h6>
|
||||
</Example>
|
||||
|
||||
## Light versions of badges
|
||||
@@ -68,13 +104,27 @@ You can use it to create a pill with numbers, for example, to show the number of
|
||||
You can use [icons](/ui/components/icon) in badges to make them more visually appealing. The example below demonstrates how to use icons in badges.
|
||||
|
||||
<Example centered>
|
||||
<BadgeList><Badge text="Star" icon="star" /> <Badge text="Heart" icon="heart" /> <Badge text="Check" icon="check" /> <Badge text="X" icon="x" /> <Badge text="Plus" icon="plus" /> <Badge text="Minus" icon="minus" /></BadgeList>
|
||||
<BadgeList>
|
||||
<Badge text="Star" icon="star" />
|
||||
<Badge text="Heart" icon="heart" />
|
||||
<Badge text="Check" icon="check" />
|
||||
<Badge text="X" icon="x" />
|
||||
<Badge text="Plus" icon="plus" />
|
||||
<Badge text="Minus" icon="minus" />
|
||||
</BadgeList>
|
||||
</Example>
|
||||
|
||||
You can also use an icon on the right side of the badge. The example below demonstrates how to use icons on the right side of badges.
|
||||
|
||||
<Example centered>
|
||||
<BadgeList><Badge text="Star" iconEnd="arrow-right" /> <Badge text="Heart" iconEnd="arrow-right" /> <Badge text="Check" iconEnd="arrow-right" /> <Badge text="X" iconEnd="arrow-right" /> <Badge text="Plus" iconEnd="arrow-right" /> <Badge text="Minus" iconEnd="arrow-right" /></BadgeList>
|
||||
<BadgeList>
|
||||
<Badge text="Star" iconEnd="arrow-right" />
|
||||
<Badge text="Heart" iconEnd="arrow-right" />
|
||||
<Badge text="Check" iconEnd="arrow-right" />
|
||||
<Badge text="X" iconEnd="arrow-right" />
|
||||
<Badge text="Plus" iconEnd="arrow-right" />
|
||||
<Badge text="Minus" iconEnd="arrow-right" />
|
||||
</BadgeList>
|
||||
</Example>
|
||||
|
||||
## Links
|
||||
@@ -82,7 +132,20 @@ You can also use an icon on the right side of the badge. The example below demon
|
||||
Place the badge within an `<a>` element if you want it to perform the function of a link and make it clickable.
|
||||
|
||||
<Example centered>
|
||||
<BadgeList><a href="#" class="badge bg-blue-lt">Blue</a> <a href="#" class="badge bg-azure-lt">Azure</a> <a href="#" class="badge bg-indigo-lt">Indigo</a> <a href="#" class="badge bg-purple-lt">Purple</a> <a href="#" class="badge bg-pink-lt">Pink</a> <a href="#" class="badge bg-red-lt">Red</a> <a href="#" class="badge bg-orange-lt">Orange</a> <a href="#" class="badge bg-yellow-lt">Yellow</a> <a href="#" class="badge bg-lime-lt">Lime</a> <a href="#" class="badge bg-green-lt">Green</a> <a href="#" class="badge bg-teal-lt">Teal</a> <a href="#" class="badge bg-cyan-lt">Cyan</a></BadgeList>
|
||||
<BadgeList>
|
||||
<a href="#" class="badge bg-blue-lt">Blue</a>
|
||||
<a href="#" class="badge bg-azure-lt">Azure</a>
|
||||
<a href="#" class="badge bg-indigo-lt">Indigo</a>
|
||||
<a href="#" class="badge bg-purple-lt">Purple</a>
|
||||
<a href="#" class="badge bg-pink-lt">Pink</a>
|
||||
<a href="#" class="badge bg-red-lt">Red</a>
|
||||
<a href="#" class="badge bg-orange-lt">Orange</a>
|
||||
<a href="#" class="badge bg-yellow-lt">Yellow</a>
|
||||
<a href="#" class="badge bg-lime-lt">Lime</a>
|
||||
<a href="#" class="badge bg-green-lt">Green</a>
|
||||
<a href="#" class="badge bg-teal-lt">Teal</a>
|
||||
<a href="#" class="badge bg-cyan-lt">Cyan</a>
|
||||
</BadgeList>
|
||||
</Example>
|
||||
|
||||
## Button with badge
|
||||
@@ -92,7 +155,11 @@ Badges can be used as parts of links or [buttons](/ui/components/button) to prov
|
||||
If you don't provide text for the badge, you end up with a small dot. This is useful for creating a simple notification button.
|
||||
|
||||
<Example centered>
|
||||
<div class="btn-list"> <button type="button" class="btn"> Notifications <Badge text="2" color="red" class="ms-2" /> </button> <button type="button" class="btn"> Inbox <Badge text="4" color="red" class="badge-notification" /> </button> <button type="button" class="btn"> Profile <Badge text="" color="red" class="badge-notification" /> </button> </div>
|
||||
<div class="btn-list">
|
||||
<button type="button" class="btn"> Notifications <Badge text="2" color="red" class="ms-2" /> </button>
|
||||
<button type="button" class="btn"> Inbox <Badge text="4" color="red" class="badge-notification" /> </button>
|
||||
<button type="button" class="btn"> Profile <Badge text="" color="red" class="badge-notification" /> </button>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Animated badges
|
||||
@@ -108,10 +175,66 @@ You can use the `.badge-blink` class to create a blinking effect. This class wil
|
||||
Use `.badge-sm` or `.badge-lg` to change badge size according to your needs. The default size is `.badge` and it is used in the examples above.
|
||||
|
||||
<Example centered vertical>
|
||||
<BadgeList> <Badge color="primary" size="sm" text="New" class="badge-sm" /> <Badge color="primary" size="sm" text="1" class="badge-pill" /> </BadgeList> <BadgeList> <Badge color="primary" text="New" class="badge-sm" /> <Badge color="primary" text="1" class="badge-pill" /> </BadgeList> <BadgeList> <Badge color="primary" size="lg" text="New" class="badge-sm" /> <Badge color="primary" size="lg" text="1" class="badge-pill" /> </BadgeList>
|
||||
<BadgeList>
|
||||
<Badge color="primary" size="sm" text="New" />
|
||||
<Badge color="primary" size="sm" text="1" class="badge-pill" />
|
||||
</BadgeList>
|
||||
<BadgeList>
|
||||
<Badge color="primary" text="New" />
|
||||
<Badge color="primary" text="1" class="badge-pill" />
|
||||
</BadgeList>
|
||||
<BadgeList>
|
||||
<Badge color="primary" size="lg" text="New" />
|
||||
<Badge color="primary" size="lg" text="1" class="badge-pill" />
|
||||
</BadgeList>
|
||||
</Example>
|
||||
|
||||
|
||||
## Outline badges
|
||||
|
||||
Use `.badge-outline` for a badge with a border and no fill. Add a `text-*` class to set its color - the border follows the text.
|
||||
|
||||
<Example centered>
|
||||
<BadgeList>
|
||||
{colors.map(([name]) => (
|
||||
<span class={`badge badge-outline text-${name}`}>{name}</span>
|
||||
))}
|
||||
</BadgeList>
|
||||
</Example>
|
||||
|
||||
## Dot badges
|
||||
|
||||
Use `.badge-dot` for a small dot with no text. It marks a state next to a label, so always keep that label readable next to it.
|
||||
|
||||
<Example centered>
|
||||
<BadgeList>
|
||||
<span class="badge badge-dot bg-green"></span>
|
||||
<span class="badge badge-dot bg-yellow"></span>
|
||||
<span class="badge badge-dot bg-red"></span>
|
||||
</BadgeList>
|
||||
</Example>
|
||||
|
||||
## Icon-only badges
|
||||
|
||||
Use `.badge-icononly` when the badge holds nothing but an icon. It removes the horizontal padding, so the icon stays centered.
|
||||
|
||||
<Example centered>
|
||||
<BadgeList>
|
||||
<Badge color="primary" class="badge-icononly" icon="star" />
|
||||
<Badge color="green" class="badge-icononly" icon="check" />
|
||||
<Badge color="red" class="badge-icononly" icon="x" />
|
||||
</BadgeList>
|
||||
</Example>
|
||||
|
||||
## Accessibility
|
||||
|
||||
A badge is text, not a control, so most of the work is in the words you put in it.
|
||||
|
||||
- A badge that only shows a color, such as `.badge-dot` or an empty notification badge, means nothing to a screen reader. Put the state in text next to it, or add an `aria-label` to the element it describes.
|
||||
- Write counts so they make sense on their own: `4 unread messages` reads better than a bare `4`. Keep the short version visible and the full version in an `aria-label` when space is tight.
|
||||
- A badge inside a button or a link is part of that control's name. Check how the whole control reads out loud before shortening the text.
|
||||
- Color alone should never carry the meaning. Pair it with a word or an icon, the same way [statuses](/ui/components/status) do.
|
||||
|
||||
## More examples
|
||||
|
||||
If you want to see more examples of badges, you can check out the [Bootstrap documentation](https://getbootstrap.com/docs/5.3/components/badge/) for badges. You can also find more examples in the Tabler [Badges](https://preview.tabler.io/badges.html) preview.
|
||||
|
||||
@@ -3,6 +3,23 @@ title: Breadcrumb
|
||||
summary: A breadcrumb is used to show the current website or app location and reduce the number of actions users need to take. It helps users navigate the website hierarchy and better understand its structure.
|
||||
description: Show the current page location with a breadcrumb trail. Help users navigate your site hierarchy and understand its structure.
|
||||
related: [/ui/components/pagination]
|
||||
source: core/scss/ui/_breadcrumbs.scss
|
||||
classnames:
|
||||
component:
|
||||
- class: breadcrumb
|
||||
desc: Container element, an ordered list
|
||||
part:
|
||||
- class: breadcrumb-item
|
||||
desc: One step in the trail
|
||||
style:
|
||||
- class: breadcrumb-arrows
|
||||
desc: Chevron between the items
|
||||
- class: breadcrumb-bullets
|
||||
desc: Bullet between the items
|
||||
- class: breadcrumb-dots
|
||||
desc: Dot between the items
|
||||
- class: breadcrumb-muted
|
||||
desc: Quieter text color for the whole trail
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
import Breadcrumb from '@ui/Breadcrumb.astro';
|
||||
@@ -53,6 +70,13 @@ You can use breadcrumbs in [headers](/ui/layout/page-headers) to show the curren
|
||||
<div class="page-header"> <div class="row align-items-center mw-100"> <div class="col"> <Breadcrumb pages={['Home', 'Library', 'Articles']} /> <h2 class="page-title"> <span class="text-truncate">How to Build a Modern Dashboard with Tabler</span> </h2> </div> <div class="col-auto"> <div class="btn-list"> <a href="#" class="btn d-none d-md-inline-flex"> <Icon name="edit" /> Edit </a> <a href="#" class="btn btn-primary">Publish</a> </div> </div> </div> </div>
|
||||
</Example>
|
||||
|
||||
## Accessibility
|
||||
|
||||
- Wrap the list in `<nav aria-label="Breadcrumb">`. That label is what tells this navigation apart from the others on the page.
|
||||
- Mark the last item with `aria-current="page"`. It is the current page, so it should not be a link.
|
||||
- Keep the separator in CSS, as Tabler does. A separator typed into the markup is read out between every item.
|
||||
- Breadcrumbs show where a page sits, not where the user has been. Keep them the same for everyone who lands on that page.
|
||||
|
||||
## SCSS variables
|
||||
|
||||
Use these SCSS variables to customize breadcrumbs. The default values are:
|
||||
|
||||
@@ -3,6 +3,55 @@ title: Button
|
||||
summary: Use a button style that best suits your design and encourages users to take the desired action. You can customize button properties to improve user experience by changing size, shape, color, and more.
|
||||
description: Create buttons in many colors, sizes, and shapes. Add icons, loading states, and social styles to guide users to the right action.
|
||||
related: [/ui/components/dropdown]
|
||||
source: core/scss/ui/_buttons.scss
|
||||
classnames:
|
||||
component:
|
||||
- class: btn
|
||||
desc: Container element, on a button or a link
|
||||
part:
|
||||
- class: btn-action
|
||||
desc: Quiet icon button for a card or a table row
|
||||
- class: btn-actions
|
||||
desc: Wrapper that groups action buttons
|
||||
- class: btn-list
|
||||
desc: Spaces several buttons in a row; add btn-list-center to center them
|
||||
- class: btn-group
|
||||
desc: Joins buttons into one control; btn-group-vertical stacks them
|
||||
- class: btn-toolbar
|
||||
desc: Groups several button groups
|
||||
- class: btn-check
|
||||
desc: Hidden input that turns a label into a toggle button
|
||||
style:
|
||||
- class: btn-outline
|
||||
desc: Transparent fill with a colored border
|
||||
- class: btn-ghost
|
||||
desc: No fill and no border until hovered
|
||||
- class: btn-link
|
||||
desc: Renders as a plain link
|
||||
modifier:
|
||||
- class: btn-pill
|
||||
desc: Fully rounded ends
|
||||
- class: btn-square
|
||||
desc: Sharp corners
|
||||
- class: btn-icon
|
||||
desc: Square button holding only an icon; it still needs an aria-label
|
||||
- class: btn-floating
|
||||
desc: Pins the button to the bottom corner of the viewport
|
||||
behavior:
|
||||
- class: btn-loading
|
||||
desc: Hides the label and draws a spinner; pair it with disabled and aria-busy
|
||||
- class: btn-animate-icon
|
||||
desc: Animates the icon on hover, with -pulse, -rotate, -shake, -tada or -move-start
|
||||
color:
|
||||
- class: btn-{color}
|
||||
desc: Any base or social color, for example btn-primary or btn-facebook
|
||||
size:
|
||||
- class: btn-sm
|
||||
desc: Small size
|
||||
- class: btn-lg
|
||||
desc: Large size
|
||||
- class: btn-xl
|
||||
desc: Extra large size
|
||||
---
|
||||
import ButtonGroup from '@ui/ButtonGroup.astro';
|
||||
import Example from '@components/Example.astro';
|
||||
@@ -14,7 +63,13 @@ import CodeDocs from '@components/CodeDocs.astro';
|
||||
As one of the most common elements of UI design, buttons have a very important function of engaging users within your website or app and guiding them in their actions. Use the `.btn` classes with the `<button>` element and add additional styling that will make your buttons serve their purpose and draw users' attention.
|
||||
|
||||
<Example centered>
|
||||
<div class="btn-list"> <a href="#" class="btn" role="button">Link</a> <button class="btn">Button</button> <input type="button" class="btn" value="Input" /> <input type="submit" class="btn" value="Submit" /> <input type="reset" class="btn" value="Reset" /> </div>
|
||||
<div class="btn-list">
|
||||
<a href="#" class="btn" role="button">Link</a>
|
||||
<button class="btn">Button</button>
|
||||
<input type="button" class="btn" value="Input" />
|
||||
<input type="submit" class="btn" value="Submit" />
|
||||
<input type="reset" class="btn" value="Reset" />
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Default button
|
||||
@@ -30,15 +85,35 @@ The standard button creates a white background and subtle hover animation. It's
|
||||
Use the button classes that correspond to the function of your button. The big range of available colors will help you show your button's purpose and make it easy to spot.
|
||||
|
||||
<Example separated centered>
|
||||
<div class="btn-list"> <a href="#" class="btn btn-primary">Primary</a> <a href="#" class="btn btn-secondary">Secondary</a> <a href="#" class="btn btn-success">Success</a> <a href="#" class="btn btn-warning">Warning</a> <a href="#" class="btn btn-danger">Danger</a> <a href="#" class="btn btn-info">Info</a> <a href="#" class="btn btn-dark">Dark</a> <a href="#" class="btn btn-light">Light</a> </div>
|
||||
<div class="btn-list">
|
||||
<a href="#" class="btn btn-primary">Primary</a>
|
||||
<a href="#" class="btn btn-secondary">Secondary</a>
|
||||
<a href="#" class="btn btn-success">Success</a>
|
||||
<a href="#" class="btn btn-warning">Warning</a>
|
||||
<a href="#" class="btn btn-danger">Danger</a>
|
||||
<a href="#" class="btn btn-info">Info</a>
|
||||
<a href="#" class="btn btn-dark">Dark</a>
|
||||
<a href="#" class="btn btn-light">Light</a>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Disabled buttons
|
||||
|
||||
Make buttons look inactive to show that an action is possible once the user meets certain criteria, such as completing the required fields to submit a form.
|
||||
|
||||
On a `button` element use the `disabled` attribute. On a link the `disabled` class only changes how it looks, so add `aria-disabled="true"` and `tabindex="-1"` as well - otherwise the link still takes focus and still follows on Enter.
|
||||
|
||||
<Example separated centered>
|
||||
<div class="btn-list"> <a href="#" class="btn btn-primary disabled">Primary</a> <a href="#" class="btn btn-secondary disabled">Secondary</a> <a href="#" class="btn btn-success disabled">Success</a> <a href="#" class="btn btn-warning disabled">Warning</a> <a href="#" class="btn btn-danger disabled">Danger</a> <a href="#" class="btn btn-info disabled">Info</a> <a href="#" class="btn btn-dark disabled">Dark</a> <a href="#" class="btn btn-light disabled">Light</a> </div>
|
||||
<div class="btn-list">
|
||||
<a href="#" class="btn btn-primary disabled" aria-disabled="true" tabindex="-1">Primary</a>
|
||||
<a href="#" class="btn btn-secondary disabled" aria-disabled="true" tabindex="-1">Secondary</a>
|
||||
<a href="#" class="btn btn-success disabled" aria-disabled="true" tabindex="-1">Success</a>
|
||||
<a href="#" class="btn btn-warning disabled" aria-disabled="true" tabindex="-1">Warning</a>
|
||||
<a href="#" class="btn btn-danger disabled" aria-disabled="true" tabindex="-1">Danger</a>
|
||||
<a href="#" class="btn btn-info disabled" aria-disabled="true" tabindex="-1">Info</a>
|
||||
<a href="#" class="btn btn-dark disabled" aria-disabled="true" tabindex="-1">Dark</a>
|
||||
<a href="#" class="btn btn-light disabled" aria-disabled="true" tabindex="-1">Light</a>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Color variations
|
||||
@@ -46,7 +121,20 @@ Make buttons look inactive to show that an action is possible once the user meet
|
||||
Choose the right color for your button to make it go well with your design and draw users' attention. Button colors can have a big influence on users' decisions, which is why it's important to choose them based on the intended purpose.
|
||||
|
||||
<Example separated centered>
|
||||
<div class="btn-list"> <a href="#" class="btn btn-blue">Blue</a> <a href="#" class="btn btn-azure">Azure</a> <a href="#" class="btn btn-indigo">Indigo</a> <a href="#" class="btn btn-purple">Purple</a> <a href="#" class="btn btn-pink">Pink</a> <a href="#" class="btn btn-red">Red</a> <a href="#" class="btn btn-orange">Orange</a> <a href="#" class="btn btn-yellow">Yellow</a> <a href="#" class="btn btn-lime">Lime</a> <a href="#" class="btn btn-green">Green</a> <a href="#" class="btn btn-teal">Teal</a> <a href="#" class="btn btn-cyan">Cyan</a> </div>
|
||||
<div class="btn-list">
|
||||
<a href="#" class="btn btn-blue">Blue</a>
|
||||
<a href="#" class="btn btn-azure">Azure</a>
|
||||
<a href="#" class="btn btn-indigo">Indigo</a>
|
||||
<a href="#" class="btn btn-purple">Purple</a>
|
||||
<a href="#" class="btn btn-pink">Pink</a>
|
||||
<a href="#" class="btn btn-red">Red</a>
|
||||
<a href="#" class="btn btn-orange">Orange</a>
|
||||
<a href="#" class="btn btn-yellow">Yellow</a>
|
||||
<a href="#" class="btn btn-lime">Lime</a>
|
||||
<a href="#" class="btn btn-green">Green</a>
|
||||
<a href="#" class="btn btn-teal">Teal</a>
|
||||
<a href="#" class="btn btn-cyan">Cyan</a>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Ghost buttons
|
||||
@@ -54,7 +142,16 @@ Choose the right color for your button to make it go well with your design and d
|
||||
Use the `.btn-ghost-*` class to make your button look simple yet aesthetically appealing. Ghost buttons help focus users' attention on the website's primary design, encouraging them to take action at the same time.
|
||||
|
||||
<Example separated vertical>
|
||||
<div class="btn-list"> <a href="#" class="btn btn-ghost-primary">Primary</a> <a href="#" class="btn btn-ghost-secondary">Secondary</a> <a href="#" class="btn btn-ghost-success">Success</a> <a href="#" class="btn btn-ghost-warning">Warning</a> <a href="#" class="btn btn-ghost-danger">Danger</a> <a href="#" class="btn btn-ghost-info">Info</a> <a href="#" class="btn btn-ghost-dark">Dark</a> <div class="p-2 bg-dark"> <a href="#" class="btn btn-ghost-light">Light</a> </div> </div>
|
||||
<div class="btn-list">
|
||||
<a href="#" class="btn btn-ghost-primary">Primary</a>
|
||||
<a href="#" class="btn btn-ghost-secondary">Secondary</a>
|
||||
<a href="#" class="btn btn-ghost-success">Success</a>
|
||||
<a href="#" class="btn btn-ghost-warning">Warning</a>
|
||||
<a href="#" class="btn btn-ghost-danger">Danger</a>
|
||||
<a href="#" class="btn btn-ghost-info">Info</a>
|
||||
<a href="#" class="btn btn-ghost-dark">Dark</a>
|
||||
<div class="p-2 bg-dark"><a href="#" class="btn btn-ghost-light">Light</a></div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Square buttons
|
||||
@@ -78,7 +175,16 @@ Add the `.btn-pill` class to your button to make it rounded and give it a modern
|
||||
Replace the default modifier class with the `.btn-outline-*` class, if you want to remove the color and the background of your button and give it a more subtle look. Outline buttons are perfect to use as secondary buttons, as they don't distract users from the main action.
|
||||
|
||||
<Example centered>
|
||||
<div class="btn-list"> <a href="#" class="btn btn-outline-primary">Primary</a> <a href="#" class="btn btn-outline-secondary">Secondary</a> <a href="#" class="btn btn-outline-success">Success</a> <a href="#" class="btn btn-outline-warning">Warning</a> <a href="#" class="btn btn-outline-danger">Danger</a> <a href="#" class="btn btn-outline-info">Info</a> <a href="#" class="btn btn-outline-dark">Dark</a> <a href="#" class="btn btn-outline-light">Light</a> </div>
|
||||
<div class="btn-list">
|
||||
<a href="#" class="btn btn-outline-primary">Primary</a>
|
||||
<a href="#" class="btn btn-outline-secondary">Secondary</a>
|
||||
<a href="#" class="btn btn-outline-success">Success</a>
|
||||
<a href="#" class="btn btn-outline-warning">Warning</a>
|
||||
<a href="#" class="btn btn-outline-danger">Danger</a>
|
||||
<a href="#" class="btn btn-outline-info">Info</a>
|
||||
<a href="#" class="btn btn-outline-dark">Dark</a>
|
||||
<a href="#" class="btn btn-outline-light">Light</a>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Button size
|
||||
@@ -86,11 +192,17 @@ Replace the default modifier class with the `.btn-outline-*` class, if you want
|
||||
Add `.btn-lg` or `.btn-sm` to change the size of your button and differentiate those which should have primary focus from those of secondary importance. Adapt the button size to your design and encourage users to take actions.
|
||||
|
||||
<Example centered>
|
||||
<div class="btn-list"> <button type="button" class="btn btn-primary btn-lg">Large button</button> <button type="button" class="btn btn-lg">Large button</button> </div>
|
||||
<div class="btn-list">
|
||||
<button type="button" class="btn btn-primary btn-lg">Large button</button>
|
||||
<button type="button" class="btn btn-lg">Large button</button>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
<Example centered>
|
||||
<div class="btn-list"> <button type="button" class="btn btn-primary btn-sm">Small button</button> <button type="button" class="btn btn-sm">Small button</button> </div>
|
||||
<div class="btn-list">
|
||||
<button type="button" class="btn btn-primary btn-sm">Small button</button>
|
||||
<button type="button" class="btn btn-sm">Small button</button>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Buttons with icons
|
||||
@@ -100,7 +212,26 @@ Label your button with text and add an icon to communicate the action and make i
|
||||
See all icons at [tabler.io/icons](https://tabler.io/icons).
|
||||
|
||||
<Example centered>
|
||||
<div class="btn-list"> <button type="button" class="btn"> <Icon name="upload" /> Upload </button> <button type="button" class="btn btn-warning"> <Icon name="heart" /> I like </button> <button type="button" class="btn btn-success"> <Icon name="check" /> I agree </button> <button type="button" class="btn btn-primary"> <Icon name="plus" /> More </button> <button type="button" class="btn btn-danger"> <Icon name="link" /> Link </button> <button type="button" class="btn btn-info"> <Icon name="message" /> Comment </button> </div>
|
||||
<div class="btn-list">
|
||||
<button type="button" class="btn">
|
||||
<Icon name="upload" /> Upload
|
||||
</button>
|
||||
<button type="button" class="btn btn-warning">
|
||||
<Icon name="heart" /> I like
|
||||
</button>
|
||||
<button type="button" class="btn btn-success">
|
||||
<Icon name="check" /> I agree
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary">
|
||||
<Icon name="plus" /> More
|
||||
</button>
|
||||
<button type="button" class="btn btn-danger">
|
||||
<Icon name="link" /> Link
|
||||
</button>
|
||||
<button type="button" class="btn btn-info">
|
||||
<Icon name="message" /> Comment
|
||||
</button>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Social buttons
|
||||
@@ -108,7 +239,50 @@ See all icons at [tabler.io/icons](https://tabler.io/icons).
|
||||
You can use the icons of popular social networking sites, which users are familiar with. Thanks to buttons with social media icons users can share content or follow a website with just one click, without leaving the website.
|
||||
|
||||
<Example separated centered hideCode>
|
||||
<div class="btn-list"> <a href="#" class="btn btn-facebook"> <Icon name="brand-facebook" /> Facebook </a> <a href="#" class="btn btn-twitter"> <Icon name="brand-twitter" /> Twitter </a> <a href="#" class="btn btn-google"> <Icon name="brand-google" /> Google </a> <a href="#" class="btn btn-youtube"> <Icon name="brand-youtube" /> Youtube </a> <a href="#" class="btn btn-vimeo"> <Icon name="brand-vimeo" /> Vimeo </a> <a href="#" class="btn btn-dribbble"> <Icon name="brand-dribbble" /> Dribbble </a> <a href="#" class="btn btn-github"> <Icon name="brand-github" /> Github </a> <a href="#" class="btn btn-instagram"> <Icon name="brand-instagram" /> Instagram </a> <a href="#" class="btn btn-pinterest"> <Icon name="brand-pinterest" /> Pinterest </a> <a href="#" class="btn btn-vk"> <Icon name="brand-vk" /> VK </a> <a href="#" class="btn btn-rss"> <Icon name="brand-rss" /> RSS </a> <a href="#" class="btn btn-flickr"> <Icon name="brand-flickr" /> Flickr </a> <a href="#" class="btn btn-bitbucket"> <Icon name="brand-bitbucket" /> Bitbucket </a> <a href="#" class="btn btn-tabler"> <Icon name="brand-tabler" /> Tabler </a> </div>
|
||||
<div class="btn-list">
|
||||
<a href="#" class="btn btn-facebook">
|
||||
<Icon name="brand-facebook" /> Facebook
|
||||
</a>
|
||||
<a href="#" class="btn btn-twitter">
|
||||
<Icon name="brand-twitter" /> Twitter
|
||||
</a>
|
||||
<a href="#" class="btn btn-google">
|
||||
<Icon name="brand-google" /> Google
|
||||
</a>
|
||||
<a href="#" class="btn btn-youtube">
|
||||
<Icon name="brand-youtube" /> Youtube
|
||||
</a>
|
||||
<a href="#" class="btn btn-vimeo">
|
||||
<Icon name="brand-vimeo" /> Vimeo
|
||||
</a>
|
||||
<a href="#" class="btn btn-dribbble">
|
||||
<Icon name="brand-dribbble" /> Dribbble
|
||||
</a>
|
||||
<a href="#" class="btn btn-github">
|
||||
<Icon name="brand-github" /> Github
|
||||
</a>
|
||||
<a href="#" class="btn btn-instagram">
|
||||
<Icon name="brand-instagram" /> Instagram
|
||||
</a>
|
||||
<a href="#" class="btn btn-pinterest">
|
||||
<Icon name="brand-pinterest" /> Pinterest
|
||||
</a>
|
||||
<a href="#" class="btn btn-vk">
|
||||
<Icon name="brand-vk" /> VK
|
||||
</a>
|
||||
<a href="#" class="btn btn-rss">
|
||||
<Icon name="brand-rss" /> RSS
|
||||
</a>
|
||||
<a href="#" class="btn btn-flickr">
|
||||
<Icon name="brand-flickr" /> Flickr
|
||||
</a>
|
||||
<a href="#" class="btn btn-bitbucket">
|
||||
<Icon name="brand-bitbucket" /> Bitbucket
|
||||
</a>
|
||||
<a href="#" class="btn btn-tabler">
|
||||
<Icon name="brand-tabler" /> Tabler
|
||||
</a>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
```html
|
||||
@@ -121,7 +295,34 @@ You can use the icons of popular social networking sites, which users are famili
|
||||
You can also add an icon without the name of a social networking site, if you want to display more buttons in a small space.
|
||||
|
||||
<Example separated vertical hideCode>
|
||||
<div class="btn-list"> <a href="#" class="btn btn-facebook btn-icon" aria-label="Button"> <Icon name="brand-facebook" /> </a> <a href="#" class="btn btn-x btn-icon" aria-label="Button"> <Icon name="brand-x" /> </a> <a href="#" class="btn btn-google btn-icon" aria-label="Button"> <Icon name="brand-google" /> </a> <a href="#" class="btn btn-youtube btn-icon" aria-label="Button"> <Icon name="brand-youtube" /> </a> <a href="#" class="btn btn-vimeo btn-icon" aria-label="Button"> <Icon name="brand-vimeo" /> </a> <a href="#" class="btn btn-dribbble btn-icon" aria-label="Button"> <Icon name="brand-dribbble" /> </a> <a href="#" class="btn btn-github btn-icon" aria-label="Button"> <Icon name="brand-github" /> </a> <a href="#" class="btn btn-instagram btn-icon" aria-label="Button"> <Icon name="brand-instagram" /> </a> <a href="#" class="btn btn-pinterest btn-icon" aria-label="Button"> <Icon name="brand-pinterest" /> </a> <a href="#" class="btn btn-vk btn-icon" aria-label="Button"> <Icon name="brand-vk" /> </a> <a href="#" class="btn btn-rss btn-icon" aria-label="Button"> <Icon name="rss" /> </a> <a href="#" class="btn btn-flickr btn-icon" aria-label="Button"> <Icon name="brand-flickr" /> </a> <a href="#" class="btn btn-bitbucket btn-icon" aria-label="Button"> <Icon name="brand-bitbucket" /> </a> <a href="#" class="btn btn-tabler btn-icon" aria-label="Button"> <Icon name="brand-tabler" /> </a> </div>
|
||||
<div class="btn-list">
|
||||
<a href="#" class="btn btn-facebook btn-icon" aria-label="Button">
|
||||
<Icon name="brand-facebook" />
|
||||
</a>
|
||||
<a href="#" class="btn btn-x btn-icon" aria-label="Button"><Icon name="brand-x" /></a>
|
||||
<a href="#" class="btn btn-google btn-icon" aria-label="Button"><Icon name="brand-google" /></a>
|
||||
<a href="#" class="btn btn-youtube btn-icon" aria-label="Button">
|
||||
<Icon name="brand-youtube" />
|
||||
</a>
|
||||
<a href="#" class="btn btn-vimeo btn-icon" aria-label="Button"><Icon name="brand-vimeo" /></a>
|
||||
<a href="#" class="btn btn-dribbble btn-icon" aria-label="Button">
|
||||
<Icon name="brand-dribbble" />
|
||||
</a>
|
||||
<a href="#" class="btn btn-github btn-icon" aria-label="Button"><Icon name="brand-github" /></a>
|
||||
<a href="#" class="btn btn-instagram btn-icon" aria-label="Button">
|
||||
<Icon name="brand-instagram" />
|
||||
</a>
|
||||
<a href="#" class="btn btn-pinterest btn-icon" aria-label="Button">
|
||||
<Icon name="brand-pinterest" />
|
||||
</a>
|
||||
<a href="#" class="btn btn-vk btn-icon" aria-label="Button"><Icon name="brand-vk" /></a>
|
||||
<a href="#" class="btn btn-rss btn-icon" aria-label="Button"><Icon name="rss" /></a>
|
||||
<a href="#" class="btn btn-flickr btn-icon" aria-label="Button"><Icon name="brand-flickr" /></a>
|
||||
<a href="#" class="btn btn-bitbucket btn-icon" aria-label="Button">
|
||||
<Icon name="brand-bitbucket" />
|
||||
</a>
|
||||
<a href="#" class="btn btn-tabler btn-icon" aria-label="Button"><Icon name="brand-tabler" /></a>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
```html
|
||||
@@ -135,7 +336,15 @@ You can also add an icon without the name of a social networking site, if you wa
|
||||
Add the `.btn-icon` class to remove unnecessary padding from your button and use an icon without any additional label. Thanks to that, you can save space and make the action easy to recognize for international users.
|
||||
|
||||
<Example separated centered hideCode>
|
||||
<div class="btn-list"> <a href="#" class="btn btn-primary btn-icon" aria-label="Button"> <Icon name="activity" /> </a> <a href="#" class="btn btn-github btn-icon" aria-label="Button"> <Icon name="brand-github" /> </a> <a href="#" class="btn btn-success btn-icon" aria-label="Button"> <Icon name="bell" /> </a> <a href="#" class="btn btn-warning btn-icon" aria-label="Button"> <Icon name="star" /> </a> <a href="#" class="btn btn-danger btn-icon" aria-label="Button"> <Icon name="trash" /> </a> <a href="#" class="btn btn-purple btn-icon" aria-label="Button"> <Icon name="chart-bar" /> </a> <a href="#" class="btn btn-icon" aria-label="Button"> <Icon name="git-merge" /> </a> </div>
|
||||
<div class="btn-list">
|
||||
<a href="#" class="btn btn-primary btn-icon" aria-label="Button"><Icon name="activity" /></a>
|
||||
<a href="#" class="btn btn-github btn-icon" aria-label="Button"><Icon name="brand-github" /></a>
|
||||
<a href="#" class="btn btn-success btn-icon" aria-label="Button"><Icon name="bell" /></a>
|
||||
<a href="#" class="btn btn-warning btn-icon" aria-label="Button"><Icon name="star" /></a>
|
||||
<a href="#" class="btn btn-danger btn-icon" aria-label="Button"><Icon name="trash" /></a>
|
||||
<a href="#" class="btn btn-purple btn-icon" aria-label="Button"><Icon name="chart-bar" /></a>
|
||||
<a href="#" class="btn btn-icon" aria-label="Button"><Icon name="git-merge" /></a>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
```html
|
||||
@@ -149,7 +358,33 @@ Add the `.btn-icon` class to remove unnecessary padding from your button and use
|
||||
Create a [dropdown](/ui/components/dropdown) button that will encourage users to click for more options. You can add a label with an icon or remove the label and add an icon on its own if you want to save space. Choose the option that will best suit your design and improve the user experience.
|
||||
|
||||
<Example centered hideCode height="260px">
|
||||
<div class="btn-list"> <div class="dropdown"> <button type="button" class="btn dropdown-toggle" data-bs-toggle="dropdown"> <Icon name="calendar" /> </button> <div class="dropdown-menu"> <a class="dropdown-item" href="#">Action</a> <a class="dropdown-item" href="#">Another action</a> </div> </div> <div class="dropdown"> <button type="button" class="btn dropdown-toggle" data-bs-toggle="dropdown"> <Icon name="calendar" /> Show calendar </button> <div class="dropdown-menu"> <a class="dropdown-item" href="#">Action</a> <a class="dropdown-item" href="#">Another action</a> </div> </div> <div class="dropdown"> <button type="button" class="btn dropdown-toggle" data-bs-toggle="dropdown">Show calendar</button> <div class="dropdown-menu"> <a class="dropdown-item" href="#">Action</a> <a class="dropdown-item" href="#">Another action</a> </div> </div> </div>
|
||||
<div class="btn-list">
|
||||
<div class="dropdown">
|
||||
<button type="button" class="btn dropdown-toggle" data-bs-toggle="dropdown">
|
||||
<Icon name="calendar" />
|
||||
</button>
|
||||
<div class="dropdown-menu">
|
||||
<a class="dropdown-item" href="#">Action</a>
|
||||
<a class="dropdown-item" href="#">Another action</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dropdown">
|
||||
<button type="button" class="btn dropdown-toggle" data-bs-toggle="dropdown">
|
||||
<Icon name="calendar" /> Show calendar
|
||||
</button>
|
||||
<div class="dropdown-menu">
|
||||
<a class="dropdown-item" href="#">Action</a>
|
||||
<a class="dropdown-item" href="#">Another action</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dropdown">
|
||||
<button type="button" class="btn dropdown-toggle" data-bs-toggle="dropdown"> Show calendar </button>
|
||||
<div class="dropdown-menu">
|
||||
<a class="dropdown-item" href="#">Action</a>
|
||||
<a class="dropdown-item" href="#">Another action</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
```html
|
||||
@@ -168,12 +403,19 @@ Create a [dropdown](/ui/components/dropdown) button that will encourage users to
|
||||
|
||||
Add the `.btn-loading` class to show a button's loading state, which can be useful in the case of operations that take longer to process. Thanks to that, users will be aware of the current state of their action and won't give it up before it's finished.
|
||||
|
||||
The class hides the label and draws a spinner in its place. It sets `pointer-events: none`, which stops the mouse but not the keyboard, so add `aria-busy="true"` and disable the control while it works.
|
||||
|
||||
<Example centered>
|
||||
<div class="btn-list"> <a href="#" class="btn btn-primary btn-loading"> Button </a> <a href="#" class="btn btn-primary btn-loading"> Loading button with loooong content </a> </div>
|
||||
<div class="btn-list">
|
||||
<button type="button" class="btn btn-primary btn-loading" aria-busy="true" disabled>Button</button>
|
||||
<button type="button" class="btn btn-primary btn-loading" aria-busy="true" disabled>Loading button with loooong content</button>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
<Example centered>
|
||||
<a href="#" class="btn btn-primary"> <span class="spinner-border spinner-border-sm me-2" role="status"></span> Button </a>
|
||||
<a href="#" class="btn btn-primary">
|
||||
<span class="spinner-border spinner-border-sm me-2" role="status"></span> Button
|
||||
</a>
|
||||
</Example>
|
||||
|
||||
## Full width buttons
|
||||
@@ -181,7 +423,8 @@ Add the `.btn-loading` class to show a button's loading state, which can be usef
|
||||
Add the `.w-100` class to make buttons span the full width of their container. This is useful for mobile-first designs or when you want buttons to take up the entire available space.
|
||||
|
||||
<Example separated>
|
||||
<a href="#" class="btn btn-primary w-100">Full width button</a> <a href="#" class="btn btn-outline-secondary w-100">Full width outline button</a>
|
||||
<a href="#" class="btn btn-primary w-100">Full width button</a>
|
||||
<a href="#" class="btn btn-outline-secondary w-100">Full width outline button</a>
|
||||
</Example>
|
||||
|
||||
## List of buttons
|
||||
@@ -189,27 +432,61 @@ Add the `.w-100` class to make buttons span the full width of their container. T
|
||||
Create a list of buttons using the `.btn-list` container to display different actions a user can take. If you add additional styling, such as colors, you will be able to focus users' attention on a particular action or suggest the result.
|
||||
|
||||
<Example centered>
|
||||
<div class="btn-list"> <a href="#" class="btn btn-success">Save changes</a> <a href="#" class="btn">Save and continue</a> <a href="#" class="btn btn-danger">Cancel</a> </div>
|
||||
<div class="btn-list">
|
||||
<a href="#" class="btn btn-success">Save changes</a>
|
||||
<a href="#" class="btn">Save and continue</a>
|
||||
<a href="#" class="btn btn-danger">Cancel</a>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
If the list is long, it will be wrapped and some buttons will be moved to the next line, keeping them all evenly spaced.
|
||||
|
||||
<Example centered>
|
||||
<div class="btn-list"> <a href="#" class="btn">One</a> <a href="#" class="btn">Two</a> <a href="#" class="btn">Three</a> <a href="#" class="btn">Four</a> <a href="#" class="btn">Five</a> <a href="#" class="btn">Six</a> <a href="#" class="btn">Seven</a> <a href="#" class="btn">Eight</a> <a href="#" class="btn">Nine</a> <a href="#" class="btn">Ten</a> <a href="#" class="btn">Eleven</a> <a href="#" class="btn">Twelve</a> <a href="#" class="btn">Thirteen</a> <a href="#" class="btn">Fourteen</a> <a href="#" class="btn">Fifteen</a> <a href="#" class="btn">Sixteen</a> <a href="#" class="btn">Seventeen</a> <a href="#" class="btn">Eighteen</a> <a href="#" class="btn">Nineteen</a> </div>
|
||||
<div class="btn-list">
|
||||
<a href="#" class="btn">One</a>
|
||||
<a href="#" class="btn">Two</a>
|
||||
<a href="#" class="btn">Three</a>
|
||||
<a href="#" class="btn">Four</a>
|
||||
<a href="#" class="btn">Five</a>
|
||||
<a href="#" class="btn">Six</a>
|
||||
<a href="#" class="btn">Seven</a>
|
||||
<a href="#" class="btn">Eight</a>
|
||||
<a href="#" class="btn">Nine</a>
|
||||
<a href="#" class="btn">Ten</a>
|
||||
<a href="#" class="btn">Eleven</a>
|
||||
<a href="#" class="btn">Twelve</a>
|
||||
<a href="#" class="btn">Thirteen</a>
|
||||
<a href="#" class="btn">Fourteen</a>
|
||||
<a href="#" class="btn">Fifteen</a>
|
||||
<a href="#" class="btn">Sixteen</a>
|
||||
<a href="#" class="btn">Seventeen</a>
|
||||
<a href="#" class="btn">Eighteen</a>
|
||||
<a href="#" class="btn">Nineteen</a>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
Use the `.text-center` or the `.text-end` modifiers to change the buttons' alignment and place them where they suit best.
|
||||
|
||||
<Example>
|
||||
<div class="btn-list justify-content-center"> <a href="#" class="btn">Save and continue</a> <a href="#" class="btn btn-primary">Save changes</a> </div>
|
||||
<div class="btn-list justify-content-center">
|
||||
<a href="#" class="btn">Save and continue</a>
|
||||
<a href="#" class="btn btn-primary">Save changes</a>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
<Example>
|
||||
<div class="btn-list justify-content-end"> <a href="#" class="btn">Save and continue</a> <a href="#" class="btn btn-primary">Save changes</a> </div>
|
||||
<div class="btn-list justify-content-end">
|
||||
<a href="#" class="btn">Save and continue</a>
|
||||
<a href="#" class="btn btn-primary">Save changes</a>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
<Example>
|
||||
<div class="btn-list"> <a href="#" class="btn btn-outline-danger me-auto">Delete</a> <a href="#" class="btn">Save and continue</a> <a href="#" class="btn btn-primary">Save changes</a> </div>
|
||||
<div class="btn-list">
|
||||
<a href="#" class="btn btn-outline-danger me-auto">Delete</a>
|
||||
<a href="#" class="btn">Save and continue</a>
|
||||
<a href="#" class="btn btn-primary">Save changes</a>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Buttons with badges
|
||||
@@ -217,7 +494,11 @@ Use the `.text-center` or the `.text-end` modifiers to change the buttons' align
|
||||
Add [badges](/ui/components/badge) to buttons to display additional information like counts, notifications, or status indicators. Badges automatically position themselves within the button layout.
|
||||
|
||||
<Example centered>
|
||||
<div class="btn-list"> <a href="#" class="btn"> Notifications <span class="badge ms-2">14</span> </a> <a href="#" class="btn"> Messages <span class="badge ms-2">3</span> </a> <a href="#" class="btn"> Alerts <span class="badge ms-2">7</span> </a> </div>
|
||||
<div class="btn-list">
|
||||
<a href="#" class="btn"> Notifications <span class="badge ms-2">14</span> </a>
|
||||
<a href="#" class="btn"> Messages <span class="badge ms-2">3</span> </a>
|
||||
<a href="#" class="btn"> Alerts <span class="badge ms-2">7</span> </a>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Buttons with avatars
|
||||
@@ -225,7 +506,17 @@ Add [badges](/ui/components/badge) to buttons to display additional information
|
||||
Use buttons with [avatars](/ui/components/avatar) to simplify the process of interaction and make your design more personalized. Buttons can contain avatars and labels or only avatars, if displayed on a smaller space.
|
||||
|
||||
<Example centered>
|
||||
<div class="btn-list"> <a href="#" class="btn"> <span class="avatar" style="background-image: url(/static/avatars/002f.jpg);" ></span> Avatar </a> <a href="#" class="btn"> <span class="avatar" style=" background-image: url(/static/avatars/002m.jpg); " ></span> Avatar </a> <a href="#" class="btn"> <span class="avatar" style=" background-image: url(/static/avatars/004f.jpg); " ></span> Avatar </a> </div>
|
||||
<div class="btn-list">
|
||||
<a href="#" class="btn">
|
||||
<span class="avatar" style="background-image: url(/static/avatars/002f.jpg);"></span> Avatar
|
||||
</a>
|
||||
<a href="#" class="btn">
|
||||
<span class="avatar" style=" background-image: url(/static/avatars/002m.jpg); "></span> Avatar
|
||||
</a>
|
||||
<a href="#" class="btn">
|
||||
<span class="avatar" style=" background-image: url(/static/avatars/004f.jpg); "></span> Avatar
|
||||
</a>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Buttons with animations on hover
|
||||
@@ -233,15 +524,42 @@ Use buttons with [avatars](/ui/components/avatar) to simplify the process of int
|
||||
Add a subtle animation effect to your buttons when users hover over them. This can enhance the interactivity and provide visual feedback to improve the user experience.
|
||||
|
||||
<Example>
|
||||
<div class="btn-list"> <a class="btn btn-animate-icon"> Save <Icon name="arrow-right" class="icon-end" /> </a> <a class="btn btn-animate-icon btn-animate-icon-rotate"> <Icon name="plus" /> Add </a> <a class="btn btn-animate-icon btn-animate-icon-shake"> <Icon name="bell" /> Notifications </a> <a class="btn btn-animate-icon btn-animate-icon-rotate"> <Icon name="settings" /> Settings </a> <a class="btn btn-animate-icon btn-animate-icon-pulse"> <Icon name="heart" /> Love </a> <a class="btn btn-animate-icon btn-animate-icon-rotate"> <Icon name="x" /> Close </a> <a class="btn btn-animate-icon btn-animate-icon-tada"> <Icon name="check" /> Confirm </a> <a class="btn btn-animate-icon"> Next <Icon name="chevron-right" class="icon-end" /> </a> <a class="btn btn-animate-icon btn-animate-icon-move-start"> <Icon name="chevron-left" /> Previous </a> </div>
|
||||
<div class="btn-list">
|
||||
<a class="btn btn-animate-icon"> Save <Icon name="arrow-right" class="icon-end" /> </a>
|
||||
<a class="btn btn-animate-icon btn-animate-icon-rotate">
|
||||
<Icon name="plus" /> Add
|
||||
</a>
|
||||
<a class="btn btn-animate-icon btn-animate-icon-shake">
|
||||
<Icon name="bell" /> Notifications
|
||||
</a>
|
||||
<a class="btn btn-animate-icon btn-animate-icon-rotate">
|
||||
<Icon name="settings" /> Settings
|
||||
</a>
|
||||
<a class="btn btn-animate-icon btn-animate-icon-pulse">
|
||||
<Icon name="heart" /> Love
|
||||
</a>
|
||||
<a class="btn btn-animate-icon btn-animate-icon-rotate">
|
||||
<Icon name="x" /> Close
|
||||
</a>
|
||||
<a class="btn btn-animate-icon btn-animate-icon-tada">
|
||||
<Icon name="check" /> Confirm
|
||||
</a>
|
||||
<a class="btn btn-animate-icon"> Next <Icon name="chevron-right" class="icon-end" /> </a>
|
||||
<a class="btn btn-animate-icon btn-animate-icon-move-start">
|
||||
<Icon name="chevron-left" /> Previous
|
||||
</a>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Button sizes
|
||||
|
||||
Use size modifiers to change the size of your buttons. Available sizes: `.btn-xs`, `.btn-sm`, default, `.btn-lg`, `.btn-xl`.
|
||||
Use size modifiers to change the size of your buttons. Available sizes: `.btn-sm`, default, `.btn-lg`, `.btn-xl`.
|
||||
|
||||
<Example separated centered vertical>
|
||||
<button type="button" class="btn btn-sm">Small button</button> <button type="button" class="btn">Default button</button> <button type="button" class="btn btn-lg">Large button</button> <button type="button" class="btn btn-xl">Extra large button</button>
|
||||
<button type="button" class="btn btn-sm">Small button</button>
|
||||
<button type="button" class="btn">Default button</button>
|
||||
<button type="button" class="btn btn-lg">Large button</button>
|
||||
<button type="button" class="btn btn-xl">Extra large button</button>
|
||||
</Example>
|
||||
|
||||
## Link buttons
|
||||
@@ -249,7 +567,10 @@ Use size modifiers to change the size of your buttons. Available sizes: `.btn-xs
|
||||
Use the `.btn-link` class to create buttons that look like links but maintain button functionality. These are useful for secondary actions that shouldn't compete with primary buttons for attention.
|
||||
|
||||
<Example centered>
|
||||
<div class="btn-list"> <a href="#" class="btn btn-link">Link button</a> <button type="button" class="btn btn-link">Link button</button> </div>
|
||||
<div class="btn-list">
|
||||
<a href="#" class="btn btn-link">Link button</a>
|
||||
<button type="button" class="btn btn-link">Link button</button>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Action buttons
|
||||
@@ -257,7 +578,12 @@ Use the `.btn-link` class to create buttons that look like links but maintain bu
|
||||
Use the `.btn-action` class to create subtle action buttons that are perfect for card headers, toolbars, or other interface elements where you want minimal visual impact.
|
||||
|
||||
<Example centered>
|
||||
<div class="btn-actions"> <a href="#" class="btn btn-action" aria-label="Edit"> <Icon name="edit" /> </a> <a href="#" class="btn btn-action" aria-label="Copy"> <Icon name="copy" /> </a> <a href="#" class="btn btn-action" aria-label="Settings"> <Icon name="settings" /> </a> <a href="#" class="btn btn-action" aria-label="Delete"> <Icon name="trash" /> </a> </div>
|
||||
<div class="btn-actions">
|
||||
<a href="#" class="btn btn-action" aria-label="Edit"><Icon name="edit" /></a>
|
||||
<a href="#" class="btn btn-action" aria-label="Copy"><Icon name="copy" /></a>
|
||||
<a href="#" class="btn btn-action" aria-label="Settings"><Icon name="settings" /></a>
|
||||
<a href="#" class="btn btn-action" aria-label="Delete"><Icon name="trash" /></a>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Action button groups
|
||||
@@ -265,7 +591,12 @@ Use the `.btn-action` class to create subtle action buttons that are perfect for
|
||||
Use the `.btn-actions` container to group multiple action buttons together. This creates a cohesive set of related actions that work well in card headers, toolbars, or other interface elements.
|
||||
|
||||
<Example centered>
|
||||
<div class="btn-actions"> <a href="#" class="btn btn-action"> <Icon name="refresh" /> </a> <a href="#" class="btn btn-action"> <Icon name="chevron-up" /> </a> <a href="#" class="btn btn-action"> <Icon name="dots-vertical" /> </a> <a href="#" class="btn btn-action"> <Icon name="x" /> </a> </div>
|
||||
<div class="btn-actions">
|
||||
<a href="#" class="btn btn-action"><Icon name="refresh" /></a>
|
||||
<a href="#" class="btn btn-action"><Icon name="chevron-up" /></a>
|
||||
<a href="#" class="btn btn-action"><Icon name="dots-vertical" /></a>
|
||||
<a href="#" class="btn btn-action"><Icon name="x" /></a>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Button groups
|
||||
@@ -273,17 +604,58 @@ Use the `.btn-actions` container to group multiple action buttons together. This
|
||||
Use button groups to combine related buttons together. Button groups are perfect for creating toolbars, [segmented controls](/ui/components/segmented-control), or any interface where multiple related actions should be visually grouped.
|
||||
|
||||
<Example centered>
|
||||
<ButtonGroup> <button type="button" class="btn">Left</button> <button type="button" class="btn">Middle</button> <button type="button" class="btn">Right</button> </ButtonGroup>
|
||||
<ButtonGroup>
|
||||
<button type="button" class="btn">Left</button>
|
||||
<button type="button" class="btn">Middle</button>
|
||||
<button type="button" class="btn">Right</button>
|
||||
</ButtonGroup>
|
||||
</Example>
|
||||
|
||||
<Example centered>
|
||||
<ButtonGroup> <input type="radio" class="btn-check" name="btn-radio" id="btn-radio-1" autocomplete="off" checked /> <label class="btn" for="btn-radio-1">Radio 1</label> <input type="radio" class="btn-check" name="btn-radio" id="btn-radio-2" autocomplete="off" /> <label class="btn" for="btn-radio-2">Radio 2</label> <input type="radio" class="btn-check" name="btn-radio" id="btn-radio-3" autocomplete="off" /> <label class="btn" for="btn-radio-3">Radio 3</label> </ButtonGroup>
|
||||
<ButtonGroup>
|
||||
<input type="radio" class="btn-check" name="btn-radio" id="btn-radio-1" autocomplete="off" checked />
|
||||
<label class="btn" for="btn-radio-1">Radio 1</label>
|
||||
<input type="radio" class="btn-check" name="btn-radio" id="btn-radio-2" autocomplete="off" />
|
||||
<label class="btn" for="btn-radio-2">Radio 2</label>
|
||||
<input type="radio" class="btn-check" name="btn-radio" id="btn-radio-3" autocomplete="off" />
|
||||
<label class="btn" for="btn-radio-3">Radio 3</label>
|
||||
</ButtonGroup>
|
||||
</Example>
|
||||
|
||||
<Example centered>
|
||||
<ButtonGroup vertical={true}> <button type="button" class="btn">Top</button> <button type="button" class="btn">Middle</button> <button type="button" class="btn">Bottom</button> </ButtonGroup>
|
||||
</Example>
|
||||
|
||||
## Centered button list
|
||||
|
||||
`btn-list` lays buttons out in a row with a consistent gap. Add `btn-list-center` to center that row, for example under an empty state or at the end of a form.
|
||||
|
||||
<Example>
|
||||
<div class="btn-list btn-list-center">
|
||||
<button type="button" class="btn btn-primary">Save</button>
|
||||
<button type="button" class="btn">Cancel</button>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Floating button
|
||||
|
||||
Add `btn-floating` to pin a button to the bottom corner of the viewport. It stays there while the page scrolls, casts a dropdown shadow, and is hidden when the page is printed. Pair it with `btn-icon` for the usual round action button.
|
||||
|
||||
```html
|
||||
<a href="#" class="btn btn-primary btn-icon btn-floating" aria-label="New message">
|
||||
<!-- SVG icon -->
|
||||
</a>
|
||||
```
|
||||
|
||||
## Accessibility
|
||||
|
||||
- Use `button` for an action and `a` for navigation. A link styled as a button still navigates, and a `button` inside a form still submits unless you set `type="button"`.
|
||||
- An icon-only button has no text, so give it an `aria-label` that says what it does. `btn-icon` only removes the horizontal padding; it does not add a name.
|
||||
- Mark a disabled link with `aria-disabled="true"` and `tabindex="-1"`. The `disabled` class is styling only.
|
||||
- Pair `btn-loading` with `aria-busy="true"` and a disabled state. The class blanks the label with `color: transparent`, so the old text is still what a screen reader reads.
|
||||
- A button that toggles something needs `aria-pressed`; one that opens a panel needs `aria-expanded`. Bootstrap sets `aria-expanded` for you on dropdown and collapse triggers.
|
||||
- Color alone should not carry the meaning. `btn-danger` looks alarming, but the label has to say what happens.
|
||||
|
||||
## SCSS variables
|
||||
|
||||
Use these SCSS variables to customize buttons. The default values are:
|
||||
|
||||
@@ -4,6 +4,27 @@ summary: Card gradients add rich color backgrounds to cards and help emphasize k
|
||||
description: Build eye-catching cards with gradient variants, directions, and animated backgrounds.
|
||||
added-in: '1.5.0'
|
||||
related: [/ui/components/card]
|
||||
source: core/scss/ui/_cards.scss
|
||||
classnames:
|
||||
component:
|
||||
- class: card-gradient
|
||||
desc: Applied with card, fills the card with a gradient
|
||||
style:
|
||||
- class: card-gradient-{preset}
|
||||
desc: Ready-made blends — disco, gold, love, mellow, ocean, psychedelic, rainbow, snow, sun
|
||||
behavior:
|
||||
- class: card-gradient-animated
|
||||
desc: Slowly shifts the gradient
|
||||
direction:
|
||||
- class: card-gradient-bottom
|
||||
desc: Starts the gradient at the bottom edge
|
||||
color:
|
||||
- class: card-gradient-{color}
|
||||
desc: Any base color as the gradient start
|
||||
- class: card-gradient-start
|
||||
desc: Sets the first color stop with a CSS custom property
|
||||
- class: card-gradient-end
|
||||
desc: Sets the second color stop
|
||||
---
|
||||
|
||||
import Example from '@components/Example.astro'
|
||||
@@ -19,7 +40,7 @@ Use the `.card-gradient` class on a `.card` element to apply the default gradien
|
||||
|
||||
The example below shows the base gradient card style.
|
||||
|
||||
<Example>
|
||||
<Example column>
|
||||
<div class="card card-gradient">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">Total Revenue</h3>
|
||||
@@ -32,7 +53,7 @@ The example below shows the base gradient card style.
|
||||
|
||||
You can change the color of card gradient by adding a color class like `.card-gradient-primary` or `.card-gradient-success` to the `.card-gradient` element. You can choose any color from [full list of available colors](/ui/base/colors).
|
||||
|
||||
<Example>
|
||||
<Example column>
|
||||
<div class="card card-gradient card-gradient-primary">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">Primary</h3>
|
||||
@@ -63,7 +84,7 @@ Here is a list of classes:
|
||||
<ul>
|
||||
{gradients.map((gradient, i) => { return ( <li class={`card-gradient-${gradient}`}>{gradient.charAt(0).toUpperCase() + gradient.slice(1)}</li> ) })}
|
||||
</ul>
|
||||
<Example>
|
||||
<Example column>
|
||||
|
||||
{gradients.map((gradient, i) => {
|
||||
return (
|
||||
@@ -87,7 +108,7 @@ Use direction modifiers to control where the gradient flow starts.
|
||||
<div class="card card-gradient card-gradient-bottom">...</div>
|
||||
```
|
||||
|
||||
<Example>
|
||||
<Example column>
|
||||
<div class="card card-gradient card-gradient-start card-gradient-purple">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">Start</h3>
|
||||
@@ -109,7 +130,7 @@ Use direction modifiers to control where the gradient flow starts.
|
||||
|
||||
Add `.card-gradient-animated` to animate gradient direction over time.
|
||||
|
||||
<Example>
|
||||
<Example column>
|
||||
<div class="card card-gradient card-gradient-rainbow card-gradient-animated">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">Animated gradient</h3>
|
||||
|
||||
@@ -3,6 +3,78 @@ title: Card
|
||||
summary: A card is a flexible user interface element that helps organize content into meaningful sections and display it across different screen sizes. It can contain smaller elements such as images, text, links, and buttons, and can act as an entry point to more detailed information.
|
||||
description: Organize content with flexible cards. Combine headers, footers, images, and actions to build sections that work on any screen size.
|
||||
related: [/ui/components/card-gradient, /ui/components/ribbon]
|
||||
source: core/scss/ui/_cards.scss
|
||||
classnames:
|
||||
component:
|
||||
- class: card
|
||||
desc: Container element
|
||||
part:
|
||||
- class: card-header
|
||||
desc: Title bar at the top
|
||||
- class: card-title
|
||||
desc: Heading, inside the header or the body
|
||||
- class: card-subtitle
|
||||
desc: Small label above the title
|
||||
- class: card-body
|
||||
desc: Content area
|
||||
- class: card-footer
|
||||
desc: Row at the bottom
|
||||
- class: card-meta
|
||||
desc: Muted secondary line, for a role or a date
|
||||
- class: card-actions
|
||||
desc: Slot for controls on the trailing edge of the header
|
||||
- class: card-btn
|
||||
desc: Full width action along the bottom edge
|
||||
- class: card-img-top
|
||||
desc: Image above the body; card-img-end rounds the trailing corners instead
|
||||
- class: card-img-overlay
|
||||
desc: Content laid over an image; add card-img-overlay-dark for a scrim
|
||||
- class: card-cover
|
||||
desc: Header with a background photo and an overlay; card-cover-blurred blurs it
|
||||
- class: card-stamp
|
||||
desc: Large decorative mark in the corner
|
||||
- class: card-status-top
|
||||
desc: Colored bar on an edge; also -bottom and -start
|
||||
- class: card-progress
|
||||
desc: Progress bar attached to the card edge
|
||||
- class: card-tabs
|
||||
desc: Wrapper for a card whose header is a row of tabs
|
||||
- class: card-header-tabs
|
||||
desc: Tabs inside the header; card-header-pills for the pill style
|
||||
- class: card-table
|
||||
desc: Table that sits flush inside the card
|
||||
- class: card-code
|
||||
desc: Replaces the body for a code block, removing the padding
|
||||
- class: card-list-group
|
||||
desc: List group that sits flush inside the card
|
||||
style:
|
||||
- class: card-borderless
|
||||
desc: Removes the border
|
||||
- class: card-transparent
|
||||
desc: Removes the background and the border
|
||||
- class: card-dashed
|
||||
desc: Dashed border, for an empty or a placeholder card
|
||||
modifier:
|
||||
- class: card-stacked
|
||||
desc: Draws a second card behind this one
|
||||
- class: card-rotate-start
|
||||
desc: Tilts the card; also -end, -left and -right
|
||||
- class: card-body-scrollable
|
||||
desc: Scrolls the body instead of growing the card
|
||||
behavior:
|
||||
- class: card-active
|
||||
desc: Marks the card as selected
|
||||
- class: card-inactive
|
||||
desc: Dims the card
|
||||
- class: card-link
|
||||
desc: Whole card is a link; -pop and -rotate add a hover effect
|
||||
size:
|
||||
- class: card-sm
|
||||
desc: Tighter padding
|
||||
- class: card-md
|
||||
desc: Default padding
|
||||
- class: card-lg
|
||||
desc: Roomier padding
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
import Icon from '@ui/Icon.astro';
|
||||
@@ -13,7 +85,9 @@ import CodeDocs from '@components/CodeDocs.astro';
|
||||
Use the `.card` and `.card-body` classes to create a card and use it as the basis for a more advanced card design. A card is a perfect way to organize content and make it look neat and tidy.
|
||||
|
||||
<Example column>
|
||||
<div class="card"> <div class="card-body"> <p>This is some text within a card body.</p> </div> </div>
|
||||
<div class="card">
|
||||
<div class="card-body"><p>This is some text within a card body.</p></div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Card padding
|
||||
@@ -23,7 +97,10 @@ You can change the padding of a newly created card. To do it, use the `.card-sm`
|
||||
Cards with the `.card-sm` class are well suited for small items such as widgets, etc., while the `.card-lg` class can be used for large blocks of text. Padding will be automatically reduced on small devices, to fit the screen size.
|
||||
|
||||
<Example column>
|
||||
<div class="card card-sm"> <div class="card-body">This is some text within a card body.</div> </div> <div class="card"> <div class="card-body">This is some text within a card body.</div> </div> <div class="card card-md"> <div class="card-body">This is some text within a card body.</div> </div> <div class="card card-lg"> <div class="card-body">This is some text within a card body.</div> </div>
|
||||
<div class="card card-sm"><div class="card-body">This is some text within a card body.</div></div>
|
||||
<div class="card"><div class="card-body">This is some text within a card body.</div></div>
|
||||
<div class="card card-md"><div class="card-body">This is some text within a card body.</div></div>
|
||||
<div class="card card-lg"><div class="card-body">This is some text within a card body.</div></div>
|
||||
</Example>
|
||||
|
||||
## Card with title
|
||||
@@ -31,7 +108,16 @@ Cards with the `.card-sm` class are well suited for small items such as widgets,
|
||||
Add a title to your card by including the `.card-title` class within `.card-body`. You can also place the title inside the `.card-header` element to separate the title from the content with a horizontal line.
|
||||
|
||||
<Example column>
|
||||
<div class="card"> <div class="card-body"> <h3 class="card-title">Card title</h3> <p class="text-secondary">This is some text within a card body.</p> </div> </div> <div class="card"> <div class="card-header"> <h3 class="card-title">Card title</h3> </div> <div class="card-body"> <p class="text-secondary">This is some text within a card body.</p> </div> </div>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">Card title</h3>
|
||||
<p class="text-secondary">This is some text within a card body.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header"><h3 class="card-title">Card title</h3></div>
|
||||
<div class="card-body"><p class="text-secondary">This is some text within a card body.</p></div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Card with title and image
|
||||
@@ -39,7 +125,13 @@ Add a title to your card by including the `.card-title` class within `.card-body
|
||||
To create a more visually appealing card, add a title and an image. Thanks to that, the card will go well with your interface design and draw users' attention.
|
||||
|
||||
<Example column>
|
||||
<div class="card"> <div class="img-responsive img-responsive-21x9 card-img-top" style="background-image: url(/static/photos/cup-of-coffee-and-an-open-book.jpg)" ></div> <div class="card-body"> <h3 class="card-title">Card with title and image</h3> <p class="text-secondary"> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aperiam deleniti fugit incidunt, iste, itaque minima neque pariatur perferendis sed suscipit velit vitae voluptatem. </p> </div> </div>
|
||||
<div class="card">
|
||||
<div class="img-responsive img-responsive-21x9 card-img-top" style="background-image: url(/static/photos/cup-of-coffee-and-an-open-book.jpg)"></div>
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">Card with title and image</h3>
|
||||
<p class="text-secondary"> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aperiam deleniti fugit incidunt, iste, itaque minima neque pariatur perferendis sed suscipit velit vitae voluptatem. </p>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Blog post card
|
||||
@@ -47,7 +139,25 @@ To create a more visually appealing card, add a title and an image. Thanks to th
|
||||
Add an image to your blog post card to make it eye-catching. You can do it by adding the image, with a `.card-img-top` class, inside the `.card` element. Thanks to the `.d-flex` and `.flex-column` classes within `.card-body`, the author details will be displayed at the bottom of the card.
|
||||
|
||||
<Example column>
|
||||
<div class="card d-flex flex-column"> <a href="#"> <img class="card-img-top" src="/static/photos/book-on-the-grass.jpg" alt="" /> </a> <div class="card-body d-flex flex-column"> <h3 class="card-title"> <a href="#">How do you know she is a witch?</a> </h3> <div class="text-secondary"> Are you suggesting that coconuts migrate? No, no, no! Yes, yes. A bit. But she's got a wart. You ... </div> <div class="d-flex align-items-center pt-4 mt-auto"> <span class="avatar" style="background-image: url(/static/avatars/023m.jpg)"></span> <div class="ms-3"> <a href="#" class="text-body">Maryjo Lebarree</a> <div class="text-secondary">3 days ago</div> </div> <div class="ms-auto"> <a href="#" class="icon d-none d-md-inline-block ms-3 text-secondary"> <Icon name="heart" /> </a> </div> </div> </div> </div>
|
||||
<div class="card d-flex flex-column">
|
||||
<a href="#"><img class="card-img-top" src="/static/photos/book-on-the-grass.jpg" alt="" /></a>
|
||||
<div class="card-body d-flex flex-column">
|
||||
<h3 class="card-title"><a href="#">How do you know she is a witch?</a></h3>
|
||||
<div class="text-secondary"> Are you suggesting that coconuts migrate? No, no, no! Yes, yes. A bit. But she's got a wart. You ... </div>
|
||||
<div class="d-flex align-items-center pt-4 mt-auto">
|
||||
<span class="avatar" style="background-image: url(/static/avatars/023m.jpg)"></span>
|
||||
<div class="ms-3">
|
||||
<a href="#" class="text-body">Maryjo Lebarree</a>
|
||||
<div class="text-secondary">3 days ago</div>
|
||||
</div>
|
||||
<div class="ms-auto">
|
||||
<a href="#" class="icon d-none d-md-inline-block ms-3 text-secondary">
|
||||
<Icon name="heart" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Row deck
|
||||
@@ -55,15 +165,53 @@ Add an image to your blog post card to make it eye-catching. You can do it by ad
|
||||
Add the `.row-deck` class to `.row`, if you want to display several cards next to one another. Thanks to that, they will all have the same height.
|
||||
|
||||
<Example>
|
||||
<div class="row row-deck"> <div class="col-md-4"> <div class="card"> <div class="card-body">Short content</div> </div> </div> <div class="col-md-4"> <div class="card"> <div class="card-body"> Extra long content of card. Lorem ipsum dolor sit amet, consetetur sadipscing elitr </div> </div> </div> <div class="col-md-4"> <div class="card"> <div class="card-body">Short content</div> </div> </div> </div>
|
||||
<div class="row row-deck">
|
||||
<div class="col-md-4">
|
||||
<div class="card"><div class="card-body">Short content</div></div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card">
|
||||
<div class="card-body"> Extra long content of card. Lorem ipsum dolor sit amet, consetetur sadipscing elitr </div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card"><div class="card-body">Short content</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Post card with aside image
|
||||
|
||||
You can also add an image on the left side of the card. To do it, add the `.card-aside` class to the element with the `.card` class. Then add the image in the `.card-aside-column` element and it will be automatically centered and scaled to the right size.
|
||||
You can also put the image beside the text instead of above it. Use a `row row-0` inside the card, give the image column a fixed width, and let the body take the rest. `object-cover` on the image keeps it filling its column without distortion.
|
||||
|
||||
<Example>
|
||||
<div class="card d-flex flex-column"> <div class="row row-0 flex-fill"> <div class="col-md-3"> <a href="#"> <img src="/static/photos/a-woman-works-on-a-laptop-at-home.jpg" class="w-100 h-100 object-cover" alt="Card side image" /> </a> </div> <div class="col"> <div class="card-body h-full d-flex flex-column"> <h3 class="card-title"> <a href="#">Shut up!</a> </h3> <div class="text-secondary"> Burn her! How do you know she is a witch? You don't frighten us, English pig-dogs! Go and boil yo... </div> <div class="d-flex align-items-center pt-4 mt-auto"> <span class="avatar" style="background-image: url(/static/avatars/029m.jpg)"></span> <div class="ms-3"> <a href="#" class="text-body">Egan Poetz</a> <div class="text-secondary">3 days ago</div> </div> <div class="ms-auto"> <a href="#" class="icon d-none d-md-inline-block ms-3 text-red"> <Icon name="heart" /> </a> </div> </div> </div> </div> </div> </div>
|
||||
<div class="card d-flex flex-column">
|
||||
<div class="row row-0 flex-fill">
|
||||
<div class="col-md-3">
|
||||
<a href="#">
|
||||
<img src="/static/photos/a-woman-works-on-a-laptop-at-home.jpg" class="w-100 h-100 object-cover" alt="Card side image" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card-body h-full d-flex flex-column">
|
||||
<h3 class="card-title"><a href="#">Shut up!</a></h3>
|
||||
<div class="text-secondary"> Burn her! How do you know she is a witch? You don't frighten us, English pig-dogs! Go and boil yo... </div>
|
||||
<div class="d-flex align-items-center pt-4 mt-auto">
|
||||
<span class="avatar" style="background-image: url(/static/avatars/029m.jpg)"></span>
|
||||
<div class="ms-3">
|
||||
<a href="#" class="text-body">Egan Poetz</a>
|
||||
<div class="text-secondary">3 days ago</div>
|
||||
</div>
|
||||
<div class="ms-auto">
|
||||
<a href="#" class="icon d-none d-md-inline-block ms-3 text-red">
|
||||
<Icon name="heart" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Color variations
|
||||
@@ -71,7 +219,26 @@ You can also add an image on the left side of the card. To do it, add the `.card
|
||||
Add a status color to your card, either at the top or on the side of the card, to customize it and make it more eye-catching. Use `card-status-*` and `bg-*` classes to change the placement and color of the status border.
|
||||
|
||||
<Example>
|
||||
<div class="row row-deck"> <div class="col-md-6"> <div class="card"> <div class="card-status-top bg-danger"></div> <div class="card-body"> <h3 class="card-title">Card with top status</h3> <p class="text-secondary"> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aperiam deleniti fugit incidunt, iste, itaque minima neque pariatur perferendis sed suscipit velit vitae voluptatem. </p> </div> </div> </div> <div class="col-md-6"> <div class="card"> <div class="card-status-start bg-green"></div> <div class="card-body"> <h3 class="card-title">Card with side status</h3> <p class="text-secondary"> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aperiam deleniti fugit incidunt, iste, itaque minima neque pariatur perferendis sed suscipit velit vitae voluptatem. </p> </div> </div> </div> </div>
|
||||
<div class="row row-deck">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-status-top bg-danger"></div>
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">Card with top status</h3>
|
||||
<p class="text-secondary"> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aperiam deleniti fugit incidunt, iste, itaque minima neque pariatur perferendis sed suscipit velit vitae voluptatem. </p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-status-start bg-green"></div>
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">Card with side status</h3>
|
||||
<p class="text-secondary"> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aperiam deleniti fugit incidunt, iste, itaque minima neque pariatur perferendis sed suscipit velit vitae voluptatem. </p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Card stamp
|
||||
@@ -81,7 +248,15 @@ Use a card stamp to put a large, faded icon in the top corner of a card. It is o
|
||||
Add a `.card-stamp` element as a direct child of the card, before the card body. Put the icon in a `.card-stamp-icon` element inside it.
|
||||
|
||||
<Example column>
|
||||
<div class="card"> <div class="card-stamp"> <div class="card-stamp-icon bg-yellow"> <Icon name="bell" /> </div> </div> <div class="card-body"> <h3 class="card-title">Card with a stamp</h3> <p class="text-secondary">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aperiam deleniti fugit incidunt, iste, itaque minima neque pariatur.</p> </div> </div>
|
||||
<div class="card">
|
||||
<div class="card-stamp">
|
||||
<div class="card-stamp-icon bg-yellow"><Icon name="bell" /></div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">Card with a stamp</h3>
|
||||
<p class="text-secondary"> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aperiam deleniti fugit incidunt, iste, itaque minima neque pariatur. </p>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Card stamp size and color
|
||||
@@ -89,7 +264,30 @@ Add a `.card-stamp` element as a direct child of the card, before the card body.
|
||||
Add the `card-stamp-lg` class to make the stamp bigger. Change the circle color with a `bg-*` class, and the icon color with a `text-*` class.
|
||||
|
||||
<Example>
|
||||
<div class="row row-deck"> <div class="col-md-6"> <div class="card"> <div class="card-stamp card-stamp-lg"> <div class="card-stamp-icon bg-primary"> <Icon name="ghost" /> </div> </div> <div class="card-body"> <h3 class="card-title">Large stamp</h3> <p class="text-secondary">The large stamp is a good fit for banners and wide cards.</p> </div> </div> </div> <div class="col-md-6"> <div class="card bg-primary text-primary-fg"> <div class="card-stamp"> <div class="card-stamp-icon bg-white text-primary"> <Icon name="star" /> </div> </div> <div class="card-body"> <h3 class="card-title">Stamp on a color card</h3> <p>Use a white circle with a colored icon on a card with a background color.</p> </div> </div> </div> </div>
|
||||
<div class="row row-deck">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-stamp card-stamp-lg">
|
||||
<div class="card-stamp-icon bg-primary"><Icon name="ghost" /></div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">Large stamp</h3>
|
||||
<p class="text-secondary">The large stamp is a good fit for banners and wide cards.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card bg-primary text-primary-fg">
|
||||
<div class="card-stamp">
|
||||
<div class="card-stamp-icon bg-white text-primary"><Icon name="star" /></div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">Stamp on a color card</h3>
|
||||
<p>Use a white circle with a colored icon on a card with a background color.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Stacked card
|
||||
@@ -97,7 +295,12 @@ Add the `card-stamp-lg` class to make the stamp bigger. Change the circle color
|
||||
Use the `card-stacked` class to stack up multiple cards, if you want to save screen space or create a visually appealing effect.
|
||||
|
||||
<Example column>
|
||||
<div class="card card-stacked"> <div class="card-body"> <h3 class="card-title">Stacked card</h3> <p class="text-secondary"> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aperiam deleniti fugit incidunt, iste, itaque minima neque pariatur perferendis sed suscipit velit vitae voluptatem. </p> </div> </div>
|
||||
<div class="card card-stacked">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">Stacked card</h3>
|
||||
<p class="text-secondary"> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aperiam deleniti fugit incidunt, iste, itaque minima neque pariatur perferendis sed suscipit velit vitae voluptatem. </p>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Tabbed card
|
||||
@@ -105,9 +308,404 @@ Use the `card-stacked` class to stack up multiple cards, if you want to save scr
|
||||
Organize multiple cards into [tabs](/ui/components/tab) to be able to display more content in a well-organized way and allow users to alternate between them easily.
|
||||
|
||||
<Example column>
|
||||
<div class="card-tabs"> <ul class="nav nav-tabs"> <li class="nav-item"> <a href="#tab-top-1" class="nav-link active" data-bs-toggle="tab">Tab 1</a> </li> <li class="nav-item"> <a href="#tab-top-2" class="nav-link" data-bs-toggle="tab">Tab 2</a> </li> <li class="nav-item"> <a href="#tab-top-3" class="nav-link" data-bs-toggle="tab">Tab 3</a> </li> <li class="nav-item"> <a href="#tab-top-4" class="nav-link" data-bs-toggle="tab">Tab 4</a> </li> </ul> <div class="tab-content"> <div id="tab-top-1" class="card tab-pane active show"> <div class="card-body"> <div class="card-title">Content of tab #1</div> <p class="text-secondary"> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Adipisci, alias aliquid distinctio dolorem expedita, fugiat hic magni molestiae molestias odit. </p> </div> </div> <div id="tab-top-2" class="card tab-pane"> <div class="card-body"> <div class="card-title">Content of tab #2</div> <p class="text-secondary"> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Adipisci, alias aliquid distinctio dolorem expedita, fugiat hic magni molestiae molestias odit. </p> </div> </div> <div id="tab-top-3" class="card tab-pane"> <div class="card-body"> <div class="card-title">Content of tab #3</div> <p class="text-secondary"> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Adipisci, alias aliquid distinctio dolorem expedita, fugiat hic magni molestiae molestias odit. </p> </div> </div> <div id="tab-top-4" class="card tab-pane"> <div class="card-body"> <div class="card-title">Content of tab #4</div> <p class="text-secondary"> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Adipisci, alias aliquid distinctio dolorem expedita, fugiat hic magni molestiae molestias odit. </p> </div> </div> </div> </div>
|
||||
<div class="card-tabs">
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="nav-item">
|
||||
<a href="#tab-top-1" class="nav-link active" data-bs-toggle="tab">Tab 1</a>
|
||||
</li>
|
||||
<li class="nav-item"><a href="#tab-top-2" class="nav-link" data-bs-toggle="tab">Tab 2</a></li>
|
||||
<li class="nav-item"><a href="#tab-top-3" class="nav-link" data-bs-toggle="tab">Tab 3</a></li>
|
||||
<li class="nav-item"><a href="#tab-top-4" class="nav-link" data-bs-toggle="tab">Tab 4</a></li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<div id="tab-top-1" class="card tab-pane active show">
|
||||
<div class="card-body">
|
||||
<div class="card-title">Content of tab #1</div>
|
||||
<p class="text-secondary"> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Adipisci, alias aliquid distinctio dolorem expedita, fugiat hic magni molestiae molestias odit. </p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="tab-top-2" class="card tab-pane">
|
||||
<div class="card-body">
|
||||
<div class="card-title">Content of tab #2</div>
|
||||
<p class="text-secondary"> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Adipisci, alias aliquid distinctio dolorem expedita, fugiat hic magni molestiae molestias odit. </p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="tab-top-3" class="card tab-pane">
|
||||
<div class="card-body">
|
||||
<div class="card-title">Content of tab #3</div>
|
||||
<p class="text-secondary"> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Adipisci, alias aliquid distinctio dolorem expedita, fugiat hic magni molestiae molestias odit. </p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="tab-top-4" class="card tab-pane">
|
||||
<div class="card-body">
|
||||
<div class="card-title">Content of tab #4</div>
|
||||
<p class="text-secondary"> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Adipisci, alias aliquid distinctio dolorem expedita, fugiat hic magni molestiae molestias odit. </p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Card status
|
||||
|
||||
Add a status color to the top, bottom or side of a card. Use `card-status-top`, `card-status-bottom` or `card-status-start` with a `bg-*` color.
|
||||
|
||||
<Example>
|
||||
<div class="row row-deck">
|
||||
<div class="col-md-4">
|
||||
<div class="card">
|
||||
<div class="card-status-top bg-primary"></div>
|
||||
<div class="card-body">Top status</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card">
|
||||
<div class="card-status-bottom bg-green"></div>
|
||||
<div class="card-body">Bottom status</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card">
|
||||
<div class="card-status-start bg-orange"></div>
|
||||
<div class="card-body">Side status</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Card progress
|
||||
|
||||
Put a progress bar at the edge of a card with `card-progress`. It squares off against the card corners, so use it as the first or the last child.
|
||||
|
||||
<Example>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">Storage</h3>
|
||||
<p class="text-secondary mb-0">484 GB of 512 GB used</p>
|
||||
</div>
|
||||
<div class="progress card-progress">
|
||||
<div class="progress-bar" style="width: 94%" role="progressbar" aria-valuenow="94" aria-valuemin="0" aria-valuemax="100" aria-label="94% used"></div>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Card actions
|
||||
|
||||
Use `card-actions` for buttons and links in a card header. It keeps them aligned with the title.
|
||||
|
||||
<Example>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">Team members</h3>
|
||||
<div class="card-actions">
|
||||
<a href="#" class="btn btn-primary">
|
||||
<Icon name="plus" /> Invite
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">Invite a teammate to this project.</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Card subtitle
|
||||
|
||||
Add `card-subtitle` above a title for a small label, such as a category or a date.
|
||||
|
||||
<Example>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<p class="card-subtitle">Reports</p>
|
||||
<h3 class="card-title">Monthly summary</h3>
|
||||
<p class="text-secondary mb-0">Every report from the last 30 days.</p>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Card surfaces
|
||||
|
||||
Change how solid a card looks. `card-borderless` drops the border, `card-dashed` draws it dashed, and `card-transparent` removes the background as well - useful for an "add new" tile.
|
||||
|
||||
<Example>
|
||||
<div class="row row-deck">
|
||||
<div class="col-md-4">
|
||||
<div class="card card-borderless">
|
||||
<div class="card-body">Borderless</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card card-dashed">
|
||||
<div class="card-body">Dashed</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card card-transparent">
|
||||
<div class="card-body text-secondary">
|
||||
<Icon name="plus" /> Add new
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Header and footer variants
|
||||
|
||||
`card-header-light` tints the header, and `card-footer-transparent` drops the footer background and its top padding.
|
||||
|
||||
<Example>
|
||||
<div class="card">
|
||||
<div class="card-header card-header-light">
|
||||
<h3 class="card-title">Invoice #4321</h3>
|
||||
</div>
|
||||
<div class="card-body">Paid on 12 May.</div>
|
||||
<div class="card-footer card-footer-transparent">
|
||||
<a href="#" class="link-primary">Download PDF</a>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Scrollable body
|
||||
|
||||
Add `card-body-scrollable` with a height to keep a long list inside the card instead of stretching it.
|
||||
|
||||
<Example>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">Changelog</h3>
|
||||
</div>
|
||||
<div class="card-body card-body-scrollable" style="height: 10rem">
|
||||
<p>Fixed the dropdown position inside a card.</p>
|
||||
<p>Added a dark variant to the image overlay.</p>
|
||||
<p>Improved the contrast of muted text.</p>
|
||||
<p>Removed the unused card options markup.</p>
|
||||
<p>Documented the scrollable card body.</p>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Table in a card
|
||||
|
||||
Add `card-table` to a table so it runs edge to edge and drops its bottom margin.
|
||||
|
||||
<Example>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">Invoices</h3>
|
||||
</div>
|
||||
<table class="table card-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Number</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>#4321</td>
|
||||
<td><span class="status status-green">Paid</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>#4322</td>
|
||||
<td><span class="status status-yellow">Pending</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Clickable card
|
||||
|
||||
Make the whole card a link with `card-link`. Add `card-link-pop` to lift it on hover, or `card-link-rotate` to tilt it.
|
||||
|
||||
<Example>
|
||||
<div class="row row-deck">
|
||||
<div class="col-md-6">
|
||||
<a href="#" class="card card-link card-link-pop">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">Lifts on hover</h3>
|
||||
<p class="text-secondary mb-0">card-link-pop</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<a href="#" class="card card-link card-link-rotate">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">Tilts on hover</h3>
|
||||
<p class="text-secondary mb-0">card-link-rotate</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Card states
|
||||
|
||||
`card-active` marks the selected card, and `card-inactive` fades one out until it is hovered.
|
||||
|
||||
<Example>
|
||||
<div class="row row-deck">
|
||||
<div class="col-md-6">
|
||||
<div class="card card-active">
|
||||
<div class="card-body">Active card</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card card-inactive">
|
||||
<div class="card-body">Inactive card</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Image overlay
|
||||
|
||||
Put content on top of an image with `card-img-overlay`. Add `card-img-overlay-dark` for a gradient that keeps light text readable.
|
||||
|
||||
<Example>
|
||||
<div class="card">
|
||||
<img src="/static/photos/a-woman-works-on-a-laptop-at-home.jpg" alt="" class="card-img" />
|
||||
<div class="card-img-overlay card-img-overlay-dark">
|
||||
<h3 class="card-title text-white">Working from home</h3>
|
||||
<p class="text-white mb-0">Text stays readable over the photo.</p>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Card cover
|
||||
|
||||
Use `card-cover` for a header with a background photo. It darkens the image with an overlay, so white text on top stays readable whatever the picture looks like. Add `card-cover-blurred` to blur the photo behind that overlay.
|
||||
|
||||
<Example>
|
||||
<div class="row row-cards">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-cover text-center text-white" style="background-image: url(/static/photos/book-on-the-grass.jpg)">
|
||||
<div class="h1 m-0">Reading list</div>
|
||||
<div class="mt-1">12 books this year</div>
|
||||
</div>
|
||||
<div class="card-body">Standard overlay.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-cover card-cover-blurred text-center text-white" style="background-image: url(/static/photos/cup-of-coffee-and-an-open-book.jpg)">
|
||||
<div class="h1 m-0">Reading list</div>
|
||||
<div class="mt-1">12 books this year</div>
|
||||
</div>
|
||||
<div class="card-body">Blurred variant.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Pills in a card header
|
||||
|
||||
Tabs in a card header take `card-header-tabs`. For the pill style, use `card-header-pills` on the same `nav`.
|
||||
|
||||
<Example>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<ul class="nav nav-pills card-header-pills">
|
||||
<li class="nav-item"><a class="nav-link active" href="#">Overview</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="#">Activity</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="#">Settings</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="card-body">Card content</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Image on the trailing side
|
||||
|
||||
`card-img-top` rounds the top corners of an image, and `card-img-end` rounds the trailing ones. Use it when the image sits beside the text rather than above it, so its corners follow the card.
|
||||
|
||||
<Example>
|
||||
<div class="card">
|
||||
<div class="row row-0">
|
||||
<div class="col">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">Card with a side image</h3>
|
||||
<div class="text-secondary">The image keeps the rounded corner on the trailing edge of the card.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<img src="/static/photos/book-on-the-grass.jpg" class="w-100 h-100 object-cover card-img-end" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Card action button
|
||||
|
||||
Use `card-btn` for a full-width action at the bottom of a card. It gets a top border, centers its content and highlights on hover, so several of them side by side read as one button bar.
|
||||
|
||||
<Example>
|
||||
<div class="card" style="max-width: 20rem">
|
||||
<div class="card-body text-center">
|
||||
<span class="avatar avatar-xl mb-3" style="background-image: url(/static/avatars/029m.jpg)"></span>
|
||||
<div class="fw-medium">Egan Poetz</div>
|
||||
<div class="card-meta">Product Manager</div>
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<a href="#" class="card-btn"><Icon name="mail" class="me-2" /> Email</a>
|
||||
<a href="#" class="card-btn"><Icon name="phone" class="me-2" /> Call</a>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
`card-meta` above is the muted secondary line that goes with a title - a role, a date, an author.
|
||||
|
||||
## Rotated card
|
||||
|
||||
Add one of the `card-rotate-*` classes to tilt a card slightly. Use it for a stack of cards or a decorative section header, not for content users have to read.
|
||||
|
||||
| Class | Tilt |
|
||||
| --- | --- |
|
||||
| `card-rotate-start` | towards the start edge |
|
||||
| `card-rotate-end` | towards the end edge |
|
||||
| `card-rotate-left` | left, regardless of text direction |
|
||||
| `card-rotate-right` | right, regardless of text direction |
|
||||
|
||||
<Example>
|
||||
<div class="row row-cards">
|
||||
<div class="col-6">
|
||||
<div class="card card-rotate-start"><div class="card-body">Rotated to the start</div></div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="card card-rotate-end"><div class="card-body">Rotated to the end</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Code in a card
|
||||
|
||||
`card-code` replaces the card body when the card holds a code block. It removes the body padding and the border the highlighter adds, so the code sits flush against the card edges.
|
||||
|
||||
<Example>
|
||||
<div class="card" style="max-width: 24rem">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">Card with code</h3>
|
||||
</div>
|
||||
<div class="card-code">
|
||||
```scss
|
||||
.card-footer {
|
||||
background: transparent;
|
||||
}
|
||||
```
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
Use it instead of `card-body`, not next to it.
|
||||
|
||||
## Accessibility
|
||||
|
||||
A card is a container, so it has no role of its own. What matters is the content inside it.
|
||||
|
||||
- Keep one heading per card and match its level to the page outline. `card-title` only sets the look, so use a real `h2`-`h4` element.
|
||||
- For a clickable card, wrap the card in a single `a` element (`card-link`) rather than putting a link only on the title. That way the whole card is one tab stop with one accessible name.
|
||||
- `card-status-*` and `card-stamp` are decoration. Never let a color or an icon be the only carrier of meaning - repeat it in text, for example with a [status](/ui/components/status) or a [badge](/ui/components/badge).
|
||||
- Give an image inside a card a real `alt` when it carries information, or an empty `alt=""` when it is decorative.
|
||||
|
||||
## SCSS variables
|
||||
|
||||
Use these SCSS variables to customize cards. The default values are:
|
||||
|
||||
@@ -2,7 +2,37 @@
|
||||
title: Carousel
|
||||
summary: A carousel is used to display multiple pieces of visual content without taking up too much space. It eliminates the need to scroll down the page to see all content and is a popular method of presenting marketing information.
|
||||
description: Display multiple images or slides in a compact carousel with indicators, captions, and automatic or manual navigation.
|
||||
related: [/ui/components/inline-player]
|
||||
related: [/ui/plugins/inline-player]
|
||||
source: core/scss/ui/_carousel.scss
|
||||
classnames:
|
||||
component:
|
||||
- class: carousel
|
||||
desc: Container element
|
||||
part:
|
||||
- class: carousel-inner
|
||||
desc: Wrapper around the slides
|
||||
- class: carousel-item
|
||||
desc: One slide
|
||||
- class: carousel-caption
|
||||
desc: Text block over a slide
|
||||
- class: carousel-indicators
|
||||
desc: Row of buttons that jump to a slide
|
||||
- class: carousel-control-prev
|
||||
desc: Previous control; use a button so it can take focus
|
||||
- class: carousel-control-next
|
||||
desc: Next control
|
||||
style:
|
||||
- class: carousel-caption-background
|
||||
desc: Adds a scrim behind the caption
|
||||
- class: carousel-indicators-dot
|
||||
desc: Round dot indicators
|
||||
- class: carousel-indicators-thumb
|
||||
desc: Thumbnail indicators
|
||||
- class: carousel-indicators-vertical
|
||||
desc: Stacks the indicators down the side
|
||||
behavior:
|
||||
- class: carousel-fade
|
||||
desc: Crossfades between slides instead of sliding
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
import CodeDocs from '@components/CodeDocs.astro';
|
||||
@@ -12,7 +42,40 @@ import CodeDocs from '@components/CodeDocs.astro';
|
||||
Use a carousel to make your website design more visually appealing for users. In the default carousel design, respective elements slide automatically and users can go to the next slide by clicking an arrow.
|
||||
|
||||
<Example>
|
||||
<div id="carousel-sample" class="carousel slide" data-bs-ride="carousel"> <div class="carousel-indicators"> <button type="button" data-bs-target="#carousel-sample" data-bs-slide-to="0" class="active" ></button> <button type="button" data-bs-target="#carousel-sample" data-bs-slide-to="1"></button> <button type="button" data-bs-target="#carousel-sample" data-bs-slide-to="2"></button> <button type="button" data-bs-target="#carousel-sample" data-bs-slide-to="3"></button> <button type="button" data-bs-target="#carousel-sample" data-bs-slide-to="4"></button> </div> <div class="carousel-inner"> <div class="carousel-item active"> <img class="d-block w-100" alt="" src="/static/photos/city-lights-reflected-in-the-water-at-night.jpg" /> </div> <div class="carousel-item"> <img class="d-block w-100" alt="" src="/static/photos/color-palette-guide-sample-colors-catalog-.jpg" /> </div> <div class="carousel-item"> <img class="d-block w-100" alt="" src="/static/photos/finances-us-dollars-and-bitcoins-currency-money.jpg" /> </div> <div class="carousel-item"> <img class="d-block w-100" alt="" src="/static/photos/tropical-palm-leaves-floral-pattern-background.jpg" /> </div> <div class="carousel-item"> <img class="d-block w-100" alt="" src="/static/photos/young-woman-working-in-a-cafe.jpg" /> </div> </div> <a class="carousel-control-prev" data-bs-target="#carousel-sample" role="button" data-bs-slide="prev" > <span class="carousel-control-prev-icon" aria-hidden="true"></span> <span class="visually-hidden">Previous</span> </a> <a class="carousel-control-next" data-bs-target="#carousel-sample" role="button" data-bs-slide="next" > <span class="carousel-control-next-icon" aria-hidden="true"></span> <span class="visually-hidden">Next</span> </a> </div>
|
||||
<div id="carousel-sample" class="carousel slide" data-bs-ride="carousel">
|
||||
<div class="carousel-indicators">
|
||||
<button type="button" data-bs-target="#carousel-sample" data-bs-slide-to="0" aria-label="Slide 1" aria-current="true" class="active"></button>
|
||||
<button type="button" data-bs-target="#carousel-sample" data-bs-slide-to="1" aria-label="Slide 2"></button>
|
||||
<button type="button" data-bs-target="#carousel-sample" data-bs-slide-to="2" aria-label="Slide 3"></button>
|
||||
<button type="button" data-bs-target="#carousel-sample" data-bs-slide-to="3" aria-label="Slide 4"></button>
|
||||
<button type="button" data-bs-target="#carousel-sample" data-bs-slide-to="4" aria-label="Slide 5"></button>
|
||||
</div>
|
||||
<div class="carousel-inner">
|
||||
<div class="carousel-item active">
|
||||
<img class="d-block w-100" alt="" src="/static/photos/city-lights-reflected-in-the-water-at-night.jpg" />
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img class="d-block w-100" alt="" src="/static/photos/color-palette-guide-sample-colors-catalog-.jpg" />
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img class="d-block w-100" alt="" src="/static/photos/finances-us-dollars-and-bitcoins-currency-money.jpg" />
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img class="d-block w-100" alt="" src="/static/photos/tropical-palm-leaves-floral-pattern-background.jpg" />
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img class="d-block w-100" alt="" src="/static/photos/young-woman-working-in-a-cafe.jpg" />
|
||||
</div>
|
||||
</div>
|
||||
<button class="carousel-control-prev" type="button" data-bs-target="#carousel-sample" data-bs-slide="prev">
|
||||
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
|
||||
<span class="visually-hidden">Previous</span>
|
||||
</button>
|
||||
<button class="carousel-control-next" type="button" data-bs-target="#carousel-sample" data-bs-slide="next">
|
||||
<span class="carousel-control-next-icon" aria-hidden="true"></span>
|
||||
<span class="visually-hidden">Next</span>
|
||||
</button>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Dots indicators
|
||||
@@ -20,7 +83,32 @@ Use a carousel to make your website design more visually appealing for users. In
|
||||
You can replace the standard indicators with dots. Just add the `carousel-indicators-dot` class to your carousel:
|
||||
|
||||
<Example>
|
||||
<div id="carousel-indicators-dot" class="carousel slide carousel-fade" data-bs-ride="carousel"> <div class="carousel-indicators carousel-indicators-dot"> <button type="button" data-bs-target="#carousel-indicators-dot" data-bs-slide-to="0" class="active" ></button> <button type="button" data-bs-target="#carousel-indicators-dot" data-bs-slide-to="1"></button> <button type="button" data-bs-target="#carousel-indicators-dot" data-bs-slide-to="2"></button> <button type="button" data-bs-target="#carousel-indicators-dot" data-bs-slide-to="3"></button> <button type="button" data-bs-target="#carousel-indicators-dot" data-bs-slide-to="4"></button> </div> <div class="carousel-inner"> <div class="carousel-item active"> <img class="d-block w-100" alt="" src="/static/photos/stylish-workspace-with-macbook-pro.jpg" /> </div> <div class="carousel-item"> <img class="d-block w-100" alt="" src="/static/photos/coffee-on-a-table-with-other-items.jpg" /> </div> <div class="carousel-item"> <img class="d-block w-100" alt="" src="/static/photos/book-on-the-grass.jpg" /> </div> <div class="carousel-item"> <img class="d-block w-100" alt="" src="/static/photos/a-woman-works-at-a-desk-with-a-laptop-and-a-cup-of-coffee.jpg" /> </div> <div class="carousel-item"> <img class="d-block w-100" alt="" src="/static/photos/people-by-a-banquet-table-full-with-food.jpg" /> </div> </div> </div>
|
||||
<div id="carousel-indicators-dot" class="carousel slide carousel-fade" data-bs-ride="carousel">
|
||||
<div class="carousel-indicators carousel-indicators-dot">
|
||||
<button type="button" data-bs-target="#carousel-indicators-dot" data-bs-slide-to="0" aria-label="Slide 1" aria-current="true" class="active"></button>
|
||||
<button type="button" data-bs-target="#carousel-indicators-dot" data-bs-slide-to="1" aria-label="Slide 2"></button>
|
||||
<button type="button" data-bs-target="#carousel-indicators-dot" data-bs-slide-to="2" aria-label="Slide 3"></button>
|
||||
<button type="button" data-bs-target="#carousel-indicators-dot" data-bs-slide-to="3" aria-label="Slide 4"></button>
|
||||
<button type="button" data-bs-target="#carousel-indicators-dot" data-bs-slide-to="4" aria-label="Slide 5"></button>
|
||||
</div>
|
||||
<div class="carousel-inner">
|
||||
<div class="carousel-item active">
|
||||
<img class="d-block w-100" alt="" src="/static/photos/stylish-workspace-with-macbook-pro.jpg" />
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img class="d-block w-100" alt="" src="/static/photos/coffee-on-a-table-with-other-items.jpg" />
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img class="d-block w-100" alt="" src="/static/photos/book-on-the-grass.jpg" />
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img class="d-block w-100" alt="" src="/static/photos/a-woman-works-at-a-desk-with-a-laptop-and-a-cup-of-coffee.jpg" />
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img class="d-block w-100" alt="" src="/static/photos/people-by-a-banquet-table-full-with-food.jpg" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Thumb indicators
|
||||
@@ -28,7 +116,32 @@ You can replace the standard indicators with dots. Just add the `carousel-indica
|
||||
The syntax is similar for thumbnails. Add class `carousel-indicators-thumb` and add `background-image` to element `[data-bs-target]`. Default thumbnails have an aspect ratio of 1:1. To change this use `ratio` utils.
|
||||
|
||||
<Example>
|
||||
<div id="carousel-indicators-thumb" class="carousel slide carousel-fade" data-bs-ride="carousel"> <div class="carousel-indicators carousel-indicators-thumb"> <button type="button" data-bs-target="#carousel-indicators-thumb" data-bs-slide-to="0" class="ratio ratio-4x3 active" style="background-image: url(/static/photos/group-of-people-sightseeing-in-the-city.jpg)" ></button> <button type="button" data-bs-target="#carousel-indicators-thumb" data-bs-slide-to="1" class="ratio ratio-4x3" style="background-image: url(/static/photos/young-woman-working-in-a-cafe.jpg)" ></button> <button type="button" data-bs-target="#carousel-indicators-thumb" data-bs-slide-to="2" class="ratio ratio-4x3" style=" background-image: url(/static/photos/soft-photo-of-woman-on-the-bed-with-the-book-and-cup-of-coffee-in-hands.jpg); " ></button> <button type="button" data-bs-target="#carousel-indicators-thumb" data-bs-slide-to="3" class="ratio ratio-4x3" style="background-image: url(/static/photos/stylish-workplace-with-computer-at-home.jpg)" ></button> <button type="button" data-bs-target="#carousel-indicators-thumb" data-bs-slide-to="4" class="ratio ratio-4x3" style="background-image: url(/static/photos/stylish-workspace-with-macbook-pro.jpg)" ></button> </div> <div class="carousel-inner"> <div class="carousel-item active"> <img class="d-block w-100" alt="" src="/static/photos/group-of-people-sightseeing-in-the-city.jpg" /> </div> <div class="carousel-item"> <img class="d-block w-100" alt="" src="/static/photos/young-woman-working-in-a-cafe.jpg" /> </div> <div class="carousel-item"> <img class="d-block w-100" alt="" src="/static/photos/soft-photo-of-woman-on-the-bed-with-the-book-and-cup-of-coffee-in-hands.jpg" /> </div> <div class="carousel-item"> <img class="d-block w-100" alt="" src="/static/photos/stylish-workplace-with-computer-at-home.jpg" /> </div> <div class="carousel-item"> <img class="d-block w-100" alt="" src="/static/photos/stylish-workspace-with-macbook-pro.jpg" /> </div> </div> </div>
|
||||
<div id="carousel-indicators-thumb" class="carousel slide carousel-fade" data-bs-ride="carousel">
|
||||
<div class="carousel-indicators carousel-indicators-thumb">
|
||||
<button type="button" data-bs-target="#carousel-indicators-thumb" data-bs-slide-to="0" aria-label="Slide 1" aria-current="true" class="ratio ratio-4x3 active" style="background-image: url(/static/photos/group-of-people-sightseeing-in-the-city.jpg)"></button>
|
||||
<button type="button" data-bs-target="#carousel-indicators-thumb" data-bs-slide-to="1" aria-label="Slide 2" class="ratio ratio-4x3" style="background-image: url(/static/photos/young-woman-working-in-a-cafe.jpg)"></button>
|
||||
<button type="button" data-bs-target="#carousel-indicators-thumb" data-bs-slide-to="2" aria-label="Slide 3" class="ratio ratio-4x3" style=" background-image: url(/static/photos/soft-photo-of-woman-on-the-bed-with-the-book-and-cup-of-coffee-in-hands.jpg); "></button>
|
||||
<button type="button" data-bs-target="#carousel-indicators-thumb" data-bs-slide-to="3" aria-label="Slide 4" class="ratio ratio-4x3" style="background-image: url(/static/photos/stylish-workplace-with-computer-at-home.jpg)"></button>
|
||||
<button type="button" data-bs-target="#carousel-indicators-thumb" data-bs-slide-to="4" aria-label="Slide 5" class="ratio ratio-4x3" style="background-image: url(/static/photos/stylish-workspace-with-macbook-pro.jpg)"></button>
|
||||
</div>
|
||||
<div class="carousel-inner">
|
||||
<div class="carousel-item active">
|
||||
<img class="d-block w-100" alt="" src="/static/photos/group-of-people-sightseeing-in-the-city.jpg" />
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img class="d-block w-100" alt="" src="/static/photos/young-woman-working-in-a-cafe.jpg" />
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img class="d-block w-100" alt="" src="/static/photos/soft-photo-of-woman-on-the-bed-with-the-book-and-cup-of-coffee-in-hands.jpg" />
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img class="d-block w-100" alt="" src="/static/photos/stylish-workplace-with-computer-at-home.jpg" />
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img class="d-block w-100" alt="" src="/static/photos/stylish-workspace-with-macbook-pro.jpg" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Vertical indicators
|
||||
@@ -36,13 +149,63 @@ The syntax is similar for thumbnails. Add class `carousel-indicators-thumb` and
|
||||
To make the indicators go to the right side, add the `carousel-indicators-vertical` class. You can combine it with other classes that are responsible for dots or thumbnails.
|
||||
|
||||
<Example>
|
||||
<div id="carousel-indicators-dot-vertical" class="carousel slide carousel-fade" data-bs-ride="carousel" > <div class="carousel-indicators carousel-indicators-vertical carousel-indicators-dot"> <button type="button" data-bs-target="#carousel-indicators-dot-vertical" data-bs-slide-to="0" class="active" ></button> <button type="button" data-bs-target="#carousel-indicators-dot-vertical" data-bs-slide-to="1" ></button> <button type="button" data-bs-target="#carousel-indicators-dot-vertical" data-bs-slide-to="2" ></button> <button type="button" data-bs-target="#carousel-indicators-dot-vertical" data-bs-slide-to="3" ></button> <button type="button" data-bs-target="#carousel-indicators-dot-vertical" data-bs-slide-to="4" ></button> </div> <div class="carousel-inner"> <div class="carousel-item active"> <img class="d-block w-100" alt="" src="/static/photos/man-looking-out-to-sea.jpg" /> </div> <div class="carousel-item"> <img class="d-block w-100" alt="" src="/static/photos/making-magic-with-fairy-lights.jpg" /> </div> <div class="carousel-item"> <img class="d-block w-100" alt="" src="/static/photos/finances-us-dollars-and-bitcoins-currency-money-5.jpg" /> </div> <div class="carousel-item"> <img class="d-block w-100" alt="" src="/static/photos/cup-of-coffee-on-table-in-cafe-2.jpg" /> </div> <div class="carousel-item"> <img class="d-block w-100" alt="" src="/static/photos/young-woman-sitting-on-the-sofa-and-working-on-her-laptop-2.jpg" /> </div> </div> </div>
|
||||
<div id="carousel-indicators-dot-vertical" class="carousel slide carousel-fade" data-bs-ride="carousel">
|
||||
<div class="carousel-indicators carousel-indicators-vertical carousel-indicators-dot">
|
||||
<button type="button" data-bs-target="#carousel-indicators-dot-vertical" data-bs-slide-to="0" aria-label="Slide 1" aria-current="true" class="active"></button>
|
||||
<button type="button" data-bs-target="#carousel-indicators-dot-vertical" data-bs-slide-to="1" aria-label="Slide 2"></button>
|
||||
<button type="button" data-bs-target="#carousel-indicators-dot-vertical" data-bs-slide-to="2" aria-label="Slide 3"></button>
|
||||
<button type="button" data-bs-target="#carousel-indicators-dot-vertical" data-bs-slide-to="3" aria-label="Slide 4"></button>
|
||||
<button type="button" data-bs-target="#carousel-indicators-dot-vertical" data-bs-slide-to="4" aria-label="Slide 5"></button>
|
||||
</div>
|
||||
<div class="carousel-inner">
|
||||
<div class="carousel-item active">
|
||||
<img class="d-block w-100" alt="" src="/static/photos/man-looking-out-to-sea.jpg" />
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img class="d-block w-100" alt="" src="/static/photos/making-magic-with-fairy-lights.jpg" />
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img class="d-block w-100" alt="" src="/static/photos/finances-us-dollars-and-bitcoins-currency-money-5.jpg" />
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img class="d-block w-100" alt="" src="/static/photos/cup-of-coffee-on-table-in-cafe-2.jpg" />
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img class="d-block w-100" alt="" src="/static/photos/young-woman-sitting-on-the-sofa-and-working-on-her-laptop-2.jpg" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
An example of adding thumbnails on the right side:
|
||||
|
||||
<Example>
|
||||
<div id="carousel-indicators-thumb-vertical" class="carousel slide carousel-fade" data-bs-ride="carousel" > <div class="carousel-indicators carousel-indicators-vertical carousel-indicators-thumb"> <button type="button" data-bs-target="#carousel-indicators-thumb-vertical" data-bs-slide-to="0" class="ratio ratio-4x3 active" style=" background-image: url(/static/photos/finances-us-dollars-and-bitcoins-currency-money.jpg); " ></button> <button type="button" data-bs-target="#carousel-indicators-thumb-vertical" data-bs-slide-to="1" class="ratio ratio-4x3" style="background-image: url(/static/photos/businesswoman-working-at-her-laptop.jpg)" ></button> <button type="button" data-bs-target="#carousel-indicators-thumb-vertical" data-bs-slide-to="2" class="ratio ratio-4x3" style="background-image: url(/static/photos/color-palette-guide-sample-colors-catalog-.jpg)" ></button> <button type="button" data-bs-target="#carousel-indicators-thumb-vertical" data-bs-slide-to="3" class="ratio ratio-4x3" style=" background-image: url(/static/photos/blue-sofa-with-pillows-in-a-designer-living-room-interior.jpg); " ></button> <button type="button" data-bs-target="#carousel-indicators-thumb-vertical" data-bs-slide-to="4" class="ratio ratio-4x3" style=" background-image: url(/static/photos/beautiful-blonde-woman-on-a-wooden-pier-by-the-lake.jpg); " ></button> </div> <div class="carousel-inner"> <div class="carousel-item active"> <img class="d-block w-100" alt="" src="/static/photos/finances-us-dollars-and-bitcoins-currency-money.jpg" /> </div> <div class="carousel-item"> <img class="d-block w-100" alt="" src="/static/photos/businesswoman-working-at-her-laptop.jpg" /> </div> <div class="carousel-item"> <img class="d-block w-100" alt="" src="/static/photos/color-palette-guide-sample-colors-catalog-.jpg" /> </div> <div class="carousel-item"> <img class="d-block w-100" alt="" src="/static/photos/blue-sofa-with-pillows-in-a-designer-living-room-interior.jpg" /> </div> <div class="carousel-item"> <img class="d-block w-100" alt="" src="/static/photos/beautiful-blonde-woman-on-a-wooden-pier-by-the-lake.jpg" /> </div> </div> </div>
|
||||
<div id="carousel-indicators-thumb-vertical" class="carousel slide carousel-fade" data-bs-ride="carousel">
|
||||
<div class="carousel-indicators carousel-indicators-vertical carousel-indicators-thumb">
|
||||
<button type="button" data-bs-target="#carousel-indicators-thumb-vertical" data-bs-slide-to="0" aria-label="Slide 1" aria-current="true" class="ratio ratio-4x3 active" style=" background-image: url(/static/photos/finances-us-dollars-and-bitcoins-currency-money.jpg); "></button>
|
||||
<button type="button" data-bs-target="#carousel-indicators-thumb-vertical" data-bs-slide-to="1" aria-label="Slide 2" class="ratio ratio-4x3" style="background-image: url(/static/photos/businesswoman-working-at-her-laptop.jpg)"></button>
|
||||
<button type="button" data-bs-target="#carousel-indicators-thumb-vertical" data-bs-slide-to="2" aria-label="Slide 3" class="ratio ratio-4x3" style="background-image: url(/static/photos/color-palette-guide-sample-colors-catalog-.jpg)"></button>
|
||||
<button type="button" data-bs-target="#carousel-indicators-thumb-vertical" data-bs-slide-to="3" aria-label="Slide 4" class="ratio ratio-4x3" style=" background-image: url(/static/photos/blue-sofa-with-pillows-in-a-designer-living-room-interior.jpg); "></button>
|
||||
<button type="button" data-bs-target="#carousel-indicators-thumb-vertical" data-bs-slide-to="4" aria-label="Slide 5" class="ratio ratio-4x3" style=" background-image: url(/static/photos/beautiful-blonde-woman-on-a-wooden-pier-by-the-lake.jpg); "></button>
|
||||
</div>
|
||||
<div class="carousel-inner">
|
||||
<div class="carousel-item active">
|
||||
<img class="d-block w-100" alt="" src="/static/photos/finances-us-dollars-and-bitcoins-currency-money.jpg" />
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img class="d-block w-100" alt="" src="/static/photos/businesswoman-working-at-her-laptop.jpg" />
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img class="d-block w-100" alt="" src="/static/photos/color-palette-guide-sample-colors-catalog-.jpg" />
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img class="d-block w-100" alt="" src="/static/photos/blue-sofa-with-pillows-in-a-designer-living-room-interior.jpg" />
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img class="d-block w-100" alt="" src="/static/photos/beautiful-blonde-woman-on-a-wooden-pier-by-the-lake.jpg" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Carousel with captions
|
||||
@@ -51,9 +214,68 @@ Add captions to your slides easily with the `.carousel-caption` element within a
|
||||
Below the `md` responsive breakpoint, the captions on the following example will be hidden as they have the `d-none` class applied to them.
|
||||
|
||||
<Example>
|
||||
<div id="carousel-captions" class="carousel slide" data-bs-ride="carousel"> <div class="carousel-inner"> <div class="carousel-item active"> <img class="d-block w-100" alt="" src="/static/photos/workplace-with-laptop-on-table-at-home-4.jpg" /> <div class="carousel-caption-background d-none d-md-block"></div> <div class="carousel-caption d-none d-md-block"> <h3>Slide label</h3> <p>Nulla vitae elit libero, a pharetra augue mollis interdum.</p> </div> </div> <div class="carousel-item"> <img class="d-block w-100" alt="" src="/static/photos/people-watching-a-presentation-in-a-room.jpg" /> <div class="carousel-caption-background d-none d-md-block"></div> <div class="carousel-caption d-none d-md-block"> <h3>Slide label</h3> <p>Nulla vitae elit libero, a pharetra augue mollis interdum.</p> </div> </div> <div class="carousel-item"> <img class="d-block w-100" alt="" src="/static/photos/people-by-a-banquet-table-full-with-food.jpg" /> <div class="carousel-caption-background d-none d-md-block"></div> <div class="carousel-caption d-none d-md-block"> <h3>Slide label</h3> <p>Nulla vitae elit libero, a pharetra augue mollis interdum.</p> </div> </div> <div class="carousel-item"> <img class="d-block w-100" alt="" src="/static/photos/books-and-purple-flowers-on-a-wooden-stool-by-the-bed.jpg" /> <div class="carousel-caption-background d-none d-md-block"></div> <div class="carousel-caption d-none d-md-block"> <h3>Slide label</h3> <p>Nulla vitae elit libero, a pharetra augue mollis interdum.</p> </div> </div> <div class="carousel-item"> <img class="d-block w-100" alt="" src="/static/photos/cup-of-coffee-and-an-open-book.jpg" /> <div class="carousel-caption-background d-none d-md-block"></div> <div class="carousel-caption d-none d-md-block"> <h3>Slide label</h3> <p>Nulla vitae elit libero, a pharetra augue mollis interdum.</p> </div> </div> </div> <a class="carousel-control-prev" data-bs-target="#carousel-captions" role="button" data-bs-slide="prev" > <span class="carousel-control-prev-icon" aria-hidden="true"></span> <span class="visually-hidden">Previous</span> </a> <a class="carousel-control-next" data-bs-target="#carousel-captions" role="button" data-bs-slide="next" > <span class="carousel-control-next-icon" aria-hidden="true"></span> <span class="visually-hidden">Next</span> </a> </div>
|
||||
<div id="carousel-captions" class="carousel slide" data-bs-ride="carousel">
|
||||
<div class="carousel-inner">
|
||||
<div class="carousel-item active">
|
||||
<img class="d-block w-100" alt="" src="/static/photos/workplace-with-laptop-on-table-at-home-4.jpg" />
|
||||
<div class="carousel-caption-background d-none d-md-block"></div>
|
||||
<div class="carousel-caption d-none d-md-block">
|
||||
<h3>Slide label</h3>
|
||||
<p>Nulla vitae elit libero, a pharetra augue mollis interdum.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img class="d-block w-100" alt="" src="/static/photos/people-watching-a-presentation-in-a-room.jpg" />
|
||||
<div class="carousel-caption-background d-none d-md-block"></div>
|
||||
<div class="carousel-caption d-none d-md-block">
|
||||
<h3>Slide label</h3>
|
||||
<p>Nulla vitae elit libero, a pharetra augue mollis interdum.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img class="d-block w-100" alt="" src="/static/photos/people-by-a-banquet-table-full-with-food.jpg" />
|
||||
<div class="carousel-caption-background d-none d-md-block"></div>
|
||||
<div class="carousel-caption d-none d-md-block">
|
||||
<h3>Slide label</h3>
|
||||
<p>Nulla vitae elit libero, a pharetra augue mollis interdum.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img class="d-block w-100" alt="" src="/static/photos/books-and-purple-flowers-on-a-wooden-stool-by-the-bed.jpg" />
|
||||
<div class="carousel-caption-background d-none d-md-block"></div>
|
||||
<div class="carousel-caption d-none d-md-block">
|
||||
<h3>Slide label</h3>
|
||||
<p>Nulla vitae elit libero, a pharetra augue mollis interdum.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img class="d-block w-100" alt="" src="/static/photos/cup-of-coffee-and-an-open-book.jpg" />
|
||||
<div class="carousel-caption-background d-none d-md-block"></div>
|
||||
<div class="carousel-caption d-none d-md-block">
|
||||
<h3>Slide label</h3>
|
||||
<p>Nulla vitae elit libero, a pharetra augue mollis interdum.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="carousel-control-prev" type="button" data-bs-target="#carousel-captions" data-bs-slide="prev">
|
||||
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
|
||||
<span class="visually-hidden">Previous</span>
|
||||
</button>
|
||||
<button class="carousel-control-next" type="button" data-bs-target="#carousel-captions" data-bs-slide="next">
|
||||
<span class="carousel-control-next-icon" aria-hidden="true"></span>
|
||||
<span class="visually-hidden">Next</span>
|
||||
</button>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Accessibility
|
||||
|
||||
- Use `button` for the previous and next controls. An `a` without `href` cannot take focus, so the carousel becomes mouse-only.
|
||||
- Give every indicator an `aria-label` such as `Slide 3`, and mark the current one with `aria-current="true"`. Without a label a screen reader announces only "button".
|
||||
- A carousel that plays on its own moves content out from under the reader. Set `data-bs-ride="false"` or give users a pause control. Bootstrap already pauses on hover and on focus.
|
||||
- Keep the slide images meaningful in `alt` text, or leave `alt=""` when the caption already says the same thing.
|
||||
- Bootstrap does not move focus when a slide changes, so anything focusable inside a hidden slide is still reachable by keyboard. Keep interactive content out of carousel slides.
|
||||
|
||||
## SCSS variables
|
||||
|
||||
Use these SCSS variables to customize the carousel. The default values are:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user