twbs / bootstrap

The most popular HTML, CSS, and JavaScript framework for developing responsive, mobile first projects on the web.
https://getbootstrap.com
MIT License
170.96k stars 78.89k forks source link

Bootstrap Web Components #28131

Closed thepassle closed 2 years ago

thepassle commented 5 years ago

Hi,

I was wondering if there have been any discussions on releasing a set of bootstrap web components; they seem to be the perfect use case for something like bootstrap.

Web Components are a set of standards that allows developers to make reusable, encapsulated and modular components using standards based APIs. More so, web components are reusable in almost any framework.

With the recent anouncement that support for IE11 will be dropped, polyfills won't even be necessary; it seems like the perfect time.

Instead of applying classes, bootstrap web components could be usable like so:

<bootstrap-button></bootstrap-button>
<bootstrap-button raised></bootstrap-button>
<bootstrap-button raised warning></bootstrap-button>
<bootstrap-button raised warning large></bootstrap-button>

etc.

There is already a community effort by @morbidick : https://github.com/morbidick/bootstrap-webcomponents

Some examples of existing web component catalogs are:

If you're interested in learning more, you can find a ton of information at:

Recommendations/tooling:

As well as these blogs:

dvmuccillo commented 5 years ago

I was wondering about it too, would be awesome to have this.

But based on the browsers that Bootstrap 5 will likely support and the need to polyfill things (a lot?), if things go on this way it'll be on a v6 realese IMO.

Also there is the main focus of trying to solve things with css whenever it's possible, so i'm curious on how things would go.

web-padawan commented 5 years ago

Thanks for starting the discussion. I recall lots of tweets of this kind under Bootstrap v5 announcements. Dropping IE11 is a good opportunity to introduce web components, too.

It has its drawbacks and edge cases, though (simple case: :slotted CSS selector is quite limited, e.g. for styling links in alerts it will require to make them direct children).

stramel commented 5 years ago

I have wanted to throw together a bunch of bootstrap webcomponents for the past 3 years. I finally decided to play around with it a bit this last week.

This is roughly what I came up with. I'm not sure how much flexibility the BS team is looking for on their components. I focused on maintaining a very similar API as what currently exists. (Haven't fully fleshed out the CSS or all the variants CSS vars)

https://stackblitz.com/edit/bs-alert?file=my-element.ts

Johann-S commented 5 years ago

I agree WebComponents can suits very well to Bootstrap, but our v5 is a huge move for us (due to the removal of jQuery) so we won't begin that in our v5, but maybe in a v6 that's possible

DanL commented 5 years ago

WebComponents would make Bootstrap super compelling for me; I've always avoided it because of the fact that you need to opt-in for the entire page, rather than picking-and-choosing what's useful.

cvrebert commented 5 years ago

Old duplicates: #18015, #14200

web-padawan commented 5 years ago

For someone interested: I have started working on a small library (5 components at the moment) which in particular provides the Web Components with CSS inspired by Bootstrap 4.

I have changed a lot, in order to use custom CSS properties for theme colors and enable automatic contrast adjustments, using hsl() and calc(). So that's quite a significant rewrite.

Demo: https://web-padawan.github.io/aybolit/ Source: https://github.com/web-padawan/aybolit/tree/master/packages/bootstrap

cyberhck commented 5 years ago

@Johann-S , hey you mentioned removal of jQuery for v5, can you point me for more info? will all the jQuery based component have separate JS function which will trigger the init instead? that'd be awesome, then I could finally use Bootstrap with react properly, that's certainly a good news.

Johann-S commented 5 years ago

Hi @cyberhck, about v5 you can find more information here: https://github.com/twbs/bootstrap/projects/11

Currently with jQuery all of our components can be initialized separately, and it'll be the case in v5 too, since Bootstrap use data-api with event delegation we'll continue to provide to auto initialization for some of our components

rpokrovskij commented 4 years ago

I'm not so sure that web components suits well for Bootstrap:

How would you break input group + prepened + append to web components ? Or form-group + input + invalid-feedback ?

E.g.

<div class="input-group">
                        <input type="text" class="form-control" id="sample-complex-id" aria-label="Amount (to the nearest dollar)">
                        <div class="input-group-append">
                            <button class="btn btn-outline-secondary dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Actions</button>
                            <div class="dropdown-menu">
                                <a class="dropdown-item" href="#"  onClick="$('#sample-complex-id').val('')">Clear</a>
                            </div>
                        </div>
</div>
<div class="valid-feedback">Looks good!</div>
<div class="invalid-feedback">Invalid!</div>

Do you see how it could be wroted with custom-elements (that have shadow doms) ?

bennypowers commented 4 years ago

@rpokrovskij Some variation of this:

<twb-input-group>
  <twb-input slot="input"></twb-input>
  <twb-dropdown id="sample-complex-id" slot="append">
    <twb-button slot="trigger">Actions</button>
    <twb-item>
      <a href="#" onclick="this.getRootNode().getElementById('sample-complex-id').reset()">Clear</a>
    </twb-item>
  </twb-dropdown>
  <output slot="valid-feedback">Looks good!</output>
  <output slot="invalid-feedback">Invalid!</output>
</twb-input-group>
blikblum commented 4 years ago

I'm not so sure that web components suits well for Bootstrap:

I share the same sentiment, at least partially, specially for layout only components.

The markup of a bootstrap web component library would not be much smaller, easier to write / learn than using div elements and classes. And also would come with a significant amount of code / runtime overhead.

The benefit i see is for instantiating javascript components, like modal, declaratively

BTW: i use Boostrap with web components (without shadow dom). The web components are for views (e.g., a page) or for sections of a view. The basic elements are still done with Bootstrap classes.

Do you see how it could be wroted with custom-elements (that have shadow doms) ?

Here is an actual implementation: https://lit-element-bootstrap.dev/component/forms

See that the markup is not much smaller than using vanilla bootstrap

Also look at the amount of code required (of one element - bs-form-group): https://github.com/nik-christou/lit-element-bootstrap/blob/master/packages/components/form/src/bs-form-group.js

rpokrovskij commented 4 years ago

Some variation of this:


<twb-input-group>
  <twb-input slot="input"></twb-input>
  <twb-dropdown id="sample-complex-id" slot="append">

Thank you. Could you formulate what kind of advantage that bring? I see it this way: there are no place for Shadow Dom - it is plain mark up. Shadow Dom is usefull when you generate some DOM inside the custom element. But Bootsrap component's are not about code generation (and your sample code confirms this).

rpokrovskij commented 4 years ago

BTW: i use Boostrap with web components (without shadow dom). The web components are for views (e.g., a page) or for sections of a view. The basic elements are still done with Bootstrap classes.

Could you share some knowledge about it? Do you add the bootsrap.css to every your Custom Element's shadow DOM ?
How you pass popper into your web component that contains "popper enabled" code? Do you use templates with some "bootsrap" html inisde?

blikblum commented 4 years ago

Do you add the bootsrap.css to every your Custom Element's shadow DOM ?

As pointed, i dont use shadow DOM, so styles are global

How you pass popper into your web component that contains "popper enabled" code?

Currently, i dont use tooltips.

Do you use templates with some "bootsrap" html inisde?

Yes.

Below is a view component

class DashboardView extends Component {
  resultRangeClick(e) {
    this.cultureResults.dayRange = e.detail.value
    this.cultureResults.fetch()
    this.requestUpdate()
  }

  render() {
    return html`
      ${pageHeader('Painel de Controle')}
      <div class="container-fluid mt--7">
        <div class="row mt-5">
          <div class="col mb-5 mb-xl-0">
            <div class="card shadow">
              <div class="card-header border-0">
                <div class="row align-items-center">
                  <div class="col">
                    <h3 class="mb-0">Resultados de Culturas</h3>
                  </div>
                  <div class="col text-right">
                    <menu-button
                      icon="calendar"
                      .value=${this.cultureResults.dayRange}
                      .items=${[
                        { name: 'Último Dia', value: 1 },
                        { name: 'Última Semana', value: 7 },
                        { name: 'Últimos 15 Dias', value: 15 },
                        { name: 'Últimos 30 Dias', value: 30 },
                        { name: 'Últimos 2 Meses', value: 60 },
                      ]}
                      @item-click=${this.resultRangeClick}
                    ></menu-button>
                  </div>
                </div>
              </div>
              <div class="table-responsive table-wrapped-column">
                <data-table
                  thead-light
                  .fields=${[
                    { title: 'Data / Hora', render: renderDateCell, styles: { width: '8%' } },
                    { title: 'Paciente', attr: 'patientname', styles: { width: '20%' } },
                    {
                      title: 'Material',
                      render: renderMaterialCell,
                      styles: { width: '5%' },
                    },
                    { title: 'Resultado', attr: 'result', styles: { width: '25%' } },
                    { title: 'Observações', attr: 'notes' },
                  ]}
                  .collection=${this.cultureResults}
                ></data-table>
              </div>
            </div>
          </div>
        </div>
      </div>
    `
  }
}

data-table is bs table component menu-button is a component around bs dropdown:

class MenuButton extends Component {
  @property({ attribute: false })
  items = []

  @property({ type: String })
  icon

  @property({ type: String })
  caption

  @property({})
  value

  @event('click', '.dropdown-item')
  itemClick(e) {
    const item = e.selectorTarget.item
    this.dispatchEvent(new CustomEvent('item-click', { bubbles: true, detail: item }))
  }

  get iconClass() {
    return this.icon ? `fa fa-${this.icon}` : null
  }

  render() {
    const item = this.value !== undefined && this.items.find(item => item.value === this.value)
    const buttonCaption = item ? item.name : this.caption
    return html`
      <button type="button" class="btn btn-sm btn-secondary dropdown-toggle" data-toggle="dropdown">
        <span class=${this.iconClass}></span>
        ${buttonCaption}
      </button>
      <div class="dropdown-menu">
        ${this.items.map(item => {
          if (item.type === 'separator') {
            return html`
              <div class="dropdown-divider"></div>
            `
          } else {
            return html`
              <a class="dropdown-item" .item=${item}>${item.name}</a>
            `
          }
        })}
      </div>
    `
  }
}

pageHeader is a function that returns a lit-html template

Izicomics commented 4 years ago

My goal is to improve Izicomics my current platform to read online comis by myself, because i think that it does not adjust to current modern times, so at the moment i am learning everything basic from HTML and more, in the topic of bootstrap which of these components do you think would be useful for my project?

bestguy commented 4 years ago

Commenting to 👍 web components but vote to please not use shadow DOM and embed Bootstrap styles, or otherwise make it difficult to change theme via a global include of Bootstrap.

Many discussions of web components seem to end up in rabbit hole of assuming that means embedding styles, and then needing ad hoc ways to theme or customize. Bootstrap is so powerful because your interface is just the class names.

Markup generation seems handy though for some of the complex components that need many tags and JS. Random example:

<bs-modal header="Modal title" open>
  Modal body text goes here.
</bs-modal>
rafalsk commented 4 years ago

We're having quite an issue with using Bootstrap within web-components. While the style-sheets import and render just fine within Shadow-DOM, the Boostrap scripts do not. We have tried multiple approaches to no avail. Including an attempt to simply import both the CSS and JavaScript file within the component. With Bootstrap 4 that wouldn't work. Shadow DOM is the only way for us to go since boundaries across components are one of our top priorities. ideas how to approach this?

tones31 commented 3 years ago

Moving everything out of the shadow dom was the best choice I ever made for my applications. Shadow dom components only make sense if you are making a standalone component and not something to be used throughout your own application. You won't have any of your common styling, etc. It also is frustrating to get web components within shadow dom to work properly.

nemethmik commented 3 years ago

Your examples are excellent @blikblum exactly this was my conclusion, too: we can use light DOM custom elements in our application perfectly fine until we need slots Even slots can be worked around by passing slotted blocks as TemplateResult properties, With a light DOM custom element you cannot implement

<my-lightdomelement>
  <h1 slot=title>My Title</h1>
  <p style="...">This is the contents</p>
</my-lightdomelement>

Instead, we can do, however - not as elegant and clean but could work, fine especially with lit-html - like so:

<my-lightdomelement 
  .title=${html`<h1>My Title</h1>`} 
  .default=${html`<p style="...">This is the contents</p>`}>
</my-lightdomelement>

So, I see no problem with using light DOM custom elements extensively, especially with brilliant tools like Lit or Microsoft FAST ( which is brutally similar to Lit, BTW).

GeoSot commented 3 years ago

Guys, I am glad for digging this out. I think it would be great, if there is any volunteer here, where can start a MR, for the alert component, in order to guide the way, and make it easier for the team to decide over an existing example

mdo commented 2 years ago

I'd be fine to see some PRs here or suggestions to pull in some other repos already doing this for the community under our @twbs umbrella, but I'm closing this out as something we don't have time for ourselves unfortunately.

ahelmi365 commented 4 months ago

Any idea how to use bootstrap inside the shadowDOM only without affecting elements outside the web component? I'm using openWC with Lit-Element

bennypowers commented 4 months ago
render() {
  return html`
    <link rel="stylesheet" href="/path/to/bootstrap.css">
    ...
  `;
}

or

import bootstrapStyles from '../shared-styles/bootstrap.css'; // use a build step to transform this into a CSSStyleSheet object

@customElement('blah-blah')
class BlahBlah extends LitElement {
  static styles = [bootstrapStyles];
  // ...
}

or

const bootstrapStyles = await fetch(bootstrapStylesUrl).then(r => r.text());
const bootstrapStyleSheet = new CSSStyleSheet();
bootstrapStyleSheet.replaceSync(bootstrapStyles);
myElement.shadowRoot.adoptedStyleSheets = [...myElement.shadowRoot.adoptedStyleSheets, bootStrapStyles];