View as Markdown

Button

Use Bootstrap button styles for actions in forms, dialogs, navigation, and more.

100%
Loading...
<div class="d-flex flex-wrap gap-2">
    <twig:Button>Primary</twig:Button>
    <twig:Button color="secondary">Secondary</twig:Button>
    <twig:Button color="success">Success</twig:Button>
    <twig:Button color="danger">Danger</twig:Button>
    <twig:Button color="warning">Warning</twig:Button>
    <twig:Button color="info">Info</twig:Button>
    <twig:Button color="light">Light</twig:Button>
    <twig:Button color="dark">Dark</twig:Button>
    <twig:Button color="link">Link</twig:Button>
</div>

Installation

php bin/console ux:install button --kit bootstrap

Install the following Composer dependencies:

composer require twig/extra-bundle twig/html-extra:^3.12.0

Install the following front-end dependencies:

npm install bootstrap@^5.3.0
# ...or with Symfony AssetMapper
php bin/console importmap:require bootstrap bootstrap/dist/css/bootstrap.min.css

Copy the following file(s) into your app:

{# @prop tag &#039;button&#039;|&#039;a&#039;|&#039;input&#039; The HTML element to render. #}
{# @prop type &#039;button&#039;|&#039;submit&#039;|&#039;reset&#039;|null The type used for button and input elements. #}
{# @prop href string|null The destination used for anchor elements. #}
{# @prop color &#039;primary&#039;|&#039;secondary&#039;|&#039;success&#039;|&#039;danger&#039;|&#039;warning&#039;|&#039;info&#039;|&#039;light&#039;|&#039;dark&#039;|&#039;link&#039;|null The Bootstrap contextual color. #}
{# @prop outline boolean Whether to use an outline style. #}
{# @prop size &#039;sm&#039;|&#039;lg&#039;|null The Bootstrap button size. #}
{# @prop disabled boolean Whether the control is disabled. #}
{# @prop value string|null The value rendered by input elements. #}
{# @prop content string The fallback label when no content block is provided. #}
{# @block content The button label and optional inline content. #}
{%- props
    tag = &#039;button&#039;,
    type = null,
    href = null,
    color = &#039;primary&#039;,
    outline = false,
    size = null,
    disabled = false,
    value = null,
    content = &#039;&#039;
-%}

{%- set final_tag = tag|lower in [&#039;a&#039;, &#039;input&#039;] ? tag|lower : &#039;button&#039; -%}
{%- set final_type = type in [&#039;button&#039;, &#039;submit&#039;, &#039;reset&#039;] ? type : &#039;button&#039; -%}
{%- set valid_colors = [&#039;primary&#039;, &#039;secondary&#039;, &#039;success&#039;, &#039;danger&#039;, &#039;warning&#039;, &#039;info&#039;, &#039;light&#039;, &#039;dark&#039;, &#039;link&#039;] -%}
{%- set classes = html_classes({
    btn: true,
    (&#039;btn-&#039; ~ (outline and color != &#039;link&#039; ? &#039;outline-&#039; : &#039;&#039;) ~ color): color in valid_colors,
    (&#039;btn-&#039; ~ size): size in [&#039;lg&#039;, &#039;sm&#039;],
    disabled: disabled and final_tag == &#039;a&#039;,
}) -%}
{%- set default_attrs = {class: classes} -%}

{%- if final_tag == &#039;a&#039; -%}
    {%- set default_attrs = default_attrs|merge({role: &#039;button&#039;}) -%}
    {%- if disabled -%}
        {%- set default_attrs = default_attrs|merge({&#039;aria-disabled&#039;: &#039;true&#039;, tabindex: &#039;-1&#039;}) -%}
    {%- else -%}
        {%- set default_attrs = default_attrs|merge({href: href not in [null, &#039;&#039;] ? href : &#039;#&#039;}) -%}
    {%- endif -%}
{%- elseif final_tag == &#039;input&#039; -%}
    {%- set default_attrs = default_attrs|merge({
        type: final_type,
        value: value ?? content,
    }) -%}
    {%- if disabled -%}
        {%- set default_attrs = default_attrs|merge({disabled: true}) -%}
    {%- endif -%}
{%- else -%}
    {%- set default_attrs = default_attrs|merge({type: final_type}) -%}
    {%- if disabled -%}
        {%- set default_attrs = default_attrs|merge({disabled: true}) -%}
    {%- endif -%}
{%- endif -%}

{%- if final_tag == &#039;input&#039; -%}
    &lt;input {{ attributes.defaults(default_attrs) }}&gt;
{%- else -%}
    &lt;{{ final_tag }} {{ attributes.defaults(default_attrs) }}&gt;
        {%- block content -%}
            {{- content -}}
        {%- endblock -%}
    &lt;/{{ final_tag }}&gt;
{%- endif -%}

Usage

<twig:Button>Save changes</twig:Button>

Accessibility

Do not rely on button color alone to communicate meaning. Use explicit labels or additional visually hidden text when needed.

Disabled links omit their href, expose aria-disabled="true", and are removed from keyboard navigation.

Examples

Base class

Use the base Bootstrap button class without a contextual color when defining a custom style.

100%
Loading...
<twig:Button :color="null">Base class</twig:Button>

Variants

Use contextual colors to communicate the purpose of an action.

100%
Loading...
<div class="d-flex flex-wrap gap-2">
    <twig:Button>Primary</twig:Button>
    <twig:Button color="secondary">Secondary</twig:Button>
    <twig:Button color="success">Success</twig:Button>
    <twig:Button color="danger">Danger</twig:Button>
    <twig:Button color="warning">Warning</twig:Button>
    <twig:Button color="info">Info</twig:Button>
    <twig:Button color="light">Light</twig:Button>
    <twig:Button color="dark">Dark</twig:Button>
    <twig:Button color="link">Link</twig:Button>
</div>

Disable text wrapping

Add Bootstrap's text-nowrap utility when a button label must remain on one line.

100%
Loading...
<twig:Button class="text-nowrap">This button label does not wrap</twig:Button>

Button tags

Render the component as a button, link, or input depending on the semantic element required.

100%
Loading...
<div class="d-flex flex-wrap gap-2">
    <twig:Button tag="a" href="#">Link</twig:Button>
    <twig:Button type="submit">Button</twig:Button>
    <twig:Button tag="input" value="Input" />
    <twig:Button tag="input" type="submit" value="Submit" />
    <twig:Button tag="input" type="reset" value="Reset" />
</div>

Outline buttons

Use outline styles for actions that need less visual weight.

100%
Loading...
<div class="d-flex flex-wrap gap-2">
    <twig:Button outline>Primary</twig:Button>
    <twig:Button color="secondary" outline>Secondary</twig:Button>
    <twig:Button color="success" outline>Success</twig:Button>
    <twig:Button color="danger" outline>Danger</twig:Button>
    <twig:Button color="warning" outline>Warning</twig:Button>
    <twig:Button color="info" outline>Info</twig:Button>
    <twig:Button color="light" outline>Light</twig:Button>
    <twig:Button color="dark" outline>Dark</twig:Button>
</div>

Sizes

Use Bootstrap's large and small sizes, or customize the component with Bootstrap CSS variables.

100%
Loading...
<div class="d-flex flex-column align-items-start gap-3">
    <div class="d-flex flex-wrap gap-2">
        <twig:Button size="lg">Large button</twig:Button>
        <twig:Button color="secondary" size="lg">Large button</twig:Button>
    </div>
    <div class="d-flex flex-wrap gap-2">
        <twig:Button size="sm">Small button</twig:Button>
        <twig:Button color="secondary" size="sm">Small button</twig:Button>
    </div>
    <twig:Button style="--bs-btn-padding-y: .25rem; --bs-btn-padding-x: .5rem; --bs-btn-font-size: .75rem;">
        Custom button
    </twig:Button>
</div>

Disabled state

Disable buttons and links while preserving the appropriate HTML and accessibility semantics.

100%
Loading...
<div class="d-flex flex-column align-items-start gap-3">
    <div class="d-flex flex-wrap gap-2">
        <twig:Button disabled>Primary button</twig:Button>
        <twig:Button color="secondary" disabled>Button</twig:Button>
        <twig:Button outline disabled>Primary button</twig:Button>
        <twig:Button color="secondary" outline disabled>Button</twig:Button>
    </div>
    <div class="d-flex flex-wrap gap-2">
        <twig:Button tag="a" disabled>Primary link</twig:Button>
        <twig:Button tag="a" color="secondary" disabled>Link</twig:Button>
    </div>
</div>

Block buttons

Combine the component with Bootstrap layout utilities to create responsive full-width buttons.

100%
Loading...
<div class="d-flex flex-column gap-4">
    <div class="d-grid gap-2">
        <twig:Button>Button</twig:Button>
        <twig:Button>Button</twig:Button>
    </div>
    <div class="d-grid gap-2 d-md-block">
        <twig:Button>Button</twig:Button>
        <twig:Button>Button</twig:Button>
    </div>
    <div class="d-grid gap-2 col-6 mx-auto">
        <twig:Button>Button</twig:Button>
        <twig:Button>Button</twig:Button>
    </div>
    <div class="d-grid gap-2 d-md-flex justify-content-md-end">
        <twig:Button class="me-md-2">Button</twig:Button>
        <twig:Button>Button</twig:Button>
    </div>
</div>

Toggle states

Use Bootstrap's button plugin for controls that toggle between pressed and unpressed states.

100%
Loading...
<div class="d-flex flex-column align-items-start gap-3">
    <div class="d-inline-flex flex-wrap gap-1">
        <twig:Button :color="null" data-bs-toggle="button">Toggle button</twig:Button>
        <twig:Button :color="null" class="active" data-bs-toggle="button" aria-pressed="true">Active toggle button</twig:Button>
        <twig:Button :color="null" disabled data-bs-toggle="button">Disabled toggle button</twig:Button>
    </div>
    <div class="d-inline-flex flex-wrap gap-1">
        <twig:Button data-bs-toggle="button">Toggle button</twig:Button>
        <twig:Button class="active" data-bs-toggle="button" aria-pressed="true">Active toggle button</twig:Button>
        <twig:Button disabled data-bs-toggle="button">Disabled toggle button</twig:Button>
    </div>
    <div class="d-inline-flex flex-wrap gap-1">
        <twig:Button tag="a" :color="null" href="#" data-bs-toggle="button">Toggle link</twig:Button>
        <twig:Button tag="a" :color="null" href="#" class="active" data-bs-toggle="button" aria-pressed="true">Active toggle link</twig:Button>
        <twig:Button tag="a" :color="null" disabled data-bs-toggle="button">Disabled toggle link</twig:Button>
    </div>
    <div class="d-inline-flex flex-wrap gap-1">
        <twig:Button tag="a" href="#" data-bs-toggle="button">Toggle link</twig:Button>
        <twig:Button tag="a" href="#" class="active" data-bs-toggle="button" aria-pressed="true">Active toggle link</twig:Button>
        <twig:Button tag="a" disabled data-bs-toggle="button">Disabled toggle link</twig:Button>
    </div>
</div>

API Reference

<twig:Button>

Prop Type Default
tag 
'button'|'a'|'input' 'button'
type 
'button'|'submit'|'reset'|null null
href 
string|null null
color 
'primary'|'secondary'|'success'|'danger'|'warning'|'info'|'light'|'dark'|'link'|null 'primary'
outline 
boolean false
size 
'sm'|'lg'|null null
disabled 
boolean false
value 
string|null null
content 
string ''
Block Description
content The button label and optional inline content.